Modularize qBittorrent API in separate file
This commit is contained in:
parent
c6d9a0c07d
commit
6d5958df3f
|
@ -1,7 +1,7 @@
|
|||
use argh::FromArgs;
|
||||
|
||||
use crate::action::ActionExec;
|
||||
use crate::api::qbittorrent::{ApiClient, RawApiClient};
|
||||
use crate::api::qbittorrent::ApiClient;
|
||||
use crate::config::Config;
|
||||
use crate::error::Error;
|
||||
|
||||
|
@ -12,9 +12,6 @@ pub struct GetAction {
|
|||
#[argh(switch)]
|
||||
/// the positional argument is a magnet link, not an infohash
|
||||
magnet: bool,
|
||||
#[argh(switch, short = 'r')]
|
||||
/// return raw JSON response from API
|
||||
raw: bool,
|
||||
#[argh(switch, short = 'j')]
|
||||
/// return parsed JSON response from API
|
||||
json: bool,
|
||||
|
@ -25,18 +22,12 @@ pub struct GetAction {
|
|||
|
||||
impl ActionExec for GetAction {
|
||||
fn exec(&self, config: &Config) -> Result<(), Error> {
|
||||
if self.raw {
|
||||
let api = RawApiClient::from_config(&config)?;
|
||||
let res = api.get(&self.torrent)?;
|
||||
println!("{}", res);
|
||||
} else {
|
||||
let api = ApiClient::from_config(&config)?;
|
||||
if let Some(t) = api.get(&self.torrent)? {
|
||||
if self.json {
|
||||
println!("{}", &serde_json::to_string(&t).unwrap());
|
||||
} else {
|
||||
println!("{}", t.hash);
|
||||
}
|
||||
let api = ApiClient::from_config(&config)?;
|
||||
if let Some(t) = api.get(&self.torrent)? {
|
||||
if self.json {
|
||||
println!("{}", &serde_json::to_string(&t).unwrap());
|
||||
} else {
|
||||
println!("{}", t.hash);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use argh::FromArgs;
|
||||
|
||||
use crate::api::qbittorrent::{ApiClient, RawApiClient};
|
||||
use crate::api::qbittorrent::ApiClient;
|
||||
use crate::Error;
|
||||
use crate::action::ActionExec;
|
||||
use crate::config::Config;
|
||||
|
@ -9,9 +9,6 @@ use crate::config::Config;
|
|||
#[argh(subcommand, name = "list")]
|
||||
/// list existing torrents on qBittorrent
|
||||
pub struct ListAction {
|
||||
#[argh(switch, short = 'r')]
|
||||
/// return raw JSON response from API
|
||||
raw: bool,
|
||||
#[argh(switch, short = 'j')]
|
||||
/// return parsed JSON response from API
|
||||
json: bool,
|
||||
|
@ -19,19 +16,15 @@ pub struct ListAction {
|
|||
|
||||
impl ActionExec for ListAction {
|
||||
fn exec(&self, config: &Config) -> Result<(), Error> {
|
||||
if self.raw {
|
||||
let api = RawApiClient::from_config(&config)?;
|
||||
println!("{}", api.list()?);
|
||||
} else {
|
||||
let api = ApiClient::from_config(&config)?;
|
||||
for torrent in api.list()? {
|
||||
if self.json {
|
||||
println!("{}", &serde_json::to_string(&torrent).unwrap());
|
||||
} else {
|
||||
println!("{}", torrent.hash);
|
||||
}
|
||||
let api = ApiClient::from_config(&config)?;
|
||||
for torrent in api.list()? {
|
||||
if self.json {
|
||||
println!("{}", &serde_json::to_string(&torrent).unwrap());
|
||||
} else {
|
||||
println!("{}", torrent.hash);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
94
src/api/qbittorrent/asynchronous.rs
Normal file
94
src/api/qbittorrent/asynchronous.rs
Normal file
|
@ -0,0 +1,94 @@
|
|||
use snafu::prelude::*;
|
||||
|
||||
use crate::Config;
|
||||
use crate::api::{Torrent, TorrentList, IntoTorrent, TorrentTracker};
|
||||
use crate::api::qbittorrent::{QBittorrentListTorrent, RawAsyncApiClient};
|
||||
use crate::error::{Error, FailedDeserializeSnafu as DeserializeError};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AsyncApiClient {
|
||||
pub raw_api: RawAsyncApiClient,
|
||||
}
|
||||
|
||||
impl AsyncApiClient {
|
||||
#[allow(dead_code)]
|
||||
pub async fn from_config(config: &Config) -> Result<AsyncApiClient, Error> {
|
||||
Self::new(&config.format_host(), &config.qbittorrent.login, &config.qbittorrent.password).await
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn new(host: &str, login: &str, password: &str) -> Result<AsyncApiClient, Error> {
|
||||
let api = RawAsyncApiClient::login(host, login, password).await?;
|
||||
|
||||
Ok(AsyncApiClient {
|
||||
raw_api: api,
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn add(&self, magnet: &str, paused: bool) -> Result<(), Error> {
|
||||
let res = self.raw_api.add(magnet, paused).await?;
|
||||
if res == "Ok." {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::message(res.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn get(&self, hash: &str) -> Result<Option<Torrent>, Error> {
|
||||
let res = self.raw_api.get(hash).await?;
|
||||
if res == "" {
|
||||
Ok(None)
|
||||
} else {
|
||||
// TODO: NOT OPTIMIZED AT ALL. API DOES NOT RETURN NAME/HASH OF TORRENT SO WE HAVE TO QUERY LIST...
|
||||
let list = self.list().await?;
|
||||
let filtered_list = list.into_iter().filter(|t| t.hash == hash).collect::<Vec<Torrent>>();
|
||||
let torrent = filtered_list.first()
|
||||
.unwrap_or_else(|| panic!("Torrent was 'get' but could not be found in 'list': {}", &hash));
|
||||
Ok(Some(torrent.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
/// This method only exists because qBittorrent API 'properties' endpoint does not return torrent name/hash
|
||||
/// so if you need to do a lot of 'get', please call 'list' once and use this method instead.
|
||||
pub async fn get_with_cached_list(&self, hash: &str, list: &TorrentList) -> Result<Option<Torrent>, Error> {
|
||||
let res = self.raw_api.get(hash).await?;
|
||||
if res == "" {
|
||||
Ok(None)
|
||||
} else {
|
||||
let filtered_list = list.clone().into_iter().filter(|t| t.hash == hash).collect::<Vec<Torrent>>();
|
||||
let torrent = filtered_list.first()
|
||||
.unwrap_or_else(|| panic!("Torrent was 'get' but could not be found in 'list': {}", &hash));
|
||||
Ok(Some(torrent.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn list(&self) -> Result<TorrentList, Error> {
|
||||
let res = self.raw_api.list().await?;
|
||||
let concrete: Vec<QBittorrentListTorrent> = serde_json::from_str(&res).context(DeserializeError)?;
|
||||
Ok(concrete.iter().map(|t| t.into_torrent()).collect())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn add_tracker(&self, hash: &str, url: &str) -> Result<(), Error> {
|
||||
let _ = self.raw_api.add_tracker(hash, url).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn get_trackers(&self, hash: &str) -> Result<Vec<TorrentTracker>, Error> {
|
||||
let res = self.raw_api.get_trackers(hash).await?;
|
||||
let concrete: Vec<TorrentTracker> = serde_json::from_str(&res).context(DeserializeError)?;
|
||||
let concrete_filter_dht = concrete.into_iter().filter(|t| t.is_tracker()).collect();
|
||||
Ok(concrete_filter_dht)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn remove_tracker(&self, hash: &str, url: &str) -> Result<(), Error> {
|
||||
let _ = self.raw_api.remove_tracker(hash, url).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -1,270 +1,10 @@
|
|||
use snafu::prelude::*;
|
||||
use qbittorrent_web_api::Api;
|
||||
use tokio::runtime::{Builder, Runtime};
|
||||
|
||||
use crate::Config;
|
||||
use crate::error::{Error, ApiSnafu as IOError, InternalApiSnafu as ApiError, FailedDeserializeSnafu as DeserializeError};
|
||||
|
||||
mod types;
|
||||
pub use types::QBittorrentPropertiesTorrent;
|
||||
pub use types::QBittorrentListTorrent;
|
||||
use crate::api::{Torrent, TorrentList, IntoTorrent, TorrentTracker};
|
||||
|
||||
pub fn blocking_runtime() -> std::io::Result<Runtime> {
|
||||
Builder::new_current_thread()
|
||||
.enable_all()
|
||||
.build()
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UnauthenticatedRawAsyncApiClient;
|
||||
|
||||
impl UnauthenticatedRawAsyncApiClient {
|
||||
pub async fn login(host: &str, login: &str, password: &str) -> Result<RawAsyncApiClient, Error> {
|
||||
Ok(RawAsyncApiClient {
|
||||
api: Api::login(host, login, password).await.context(ApiError)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RawAsyncApiClient {
|
||||
pub api: qbittorrent_web_api::api_impl::Authenticated,
|
||||
}
|
||||
|
||||
impl RawAsyncApiClient {
|
||||
#[allow(dead_code)]
|
||||
pub async fn add(&self, magnet: &str, paused: bool) -> Result<String, Error> {
|
||||
if paused {
|
||||
self.api.torrent_management().add(magnet).paused("true").send_raw().await.context(ApiError)
|
||||
} else {
|
||||
self.api.torrent_management().add(magnet).send_raw().await.context(ApiError)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn get(&self, hash: &str) -> Result<String, Error> {
|
||||
self.api.torrent_management().properties_raw(hash).await.context(ApiError)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn list(&self) -> Result<String, Error> {
|
||||
self.api.torrent_management().info().send_raw().await.context(ApiError)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn add_tracker(&self, hash: &str, url: &str) -> Result<String, Error> {
|
||||
self.api.torrent_management().add_trackers_raw(hash, url).await.context(ApiError)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn get_trackers(&self, hash: &str) -> Result<String, Error> {
|
||||
self.api.torrent_management().trackers_raw(hash).await.context(ApiError)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn remove_tracker(&self, hash: &str, url: &str) -> Result<String, Error> {
|
||||
self.api.torrent_management().remove_trackers_raw(hash, &vec!(url)).await.context(ApiError)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RawApiClient {
|
||||
pub rt: Runtime,
|
||||
pub api: RawAsyncApiClient,
|
||||
}
|
||||
|
||||
impl RawApiClient {
|
||||
pub fn from_config(config: &Config) -> Result<RawApiClient, Error> {
|
||||
Self::new(&config.format_host(), &config.qbittorrent.login, &config.qbittorrent.password)
|
||||
}
|
||||
|
||||
/// Login into a qBittorrent backend and return a proper ApiClient instance
|
||||
#[allow(dead_code)]
|
||||
pub fn new(host: &str, login: &str, password: &str) -> Result<RawApiClient, Error> {
|
||||
let rt = blocking_runtime().context(IOError)?;
|
||||
let api = rt.block_on(UnauthenticatedRawAsyncApiClient::login(host, login, password))?;
|
||||
Ok(RawApiClient {
|
||||
rt,
|
||||
api,
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn add(&self, magnet: &str, paused: bool) -> Result<String, Error> {
|
||||
self.rt.block_on(self.api.add(magnet, paused))
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn get(&self, hash: &str) -> Result<String, Error> {
|
||||
self.rt.block_on(self.api.get(hash))
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn list(&self) -> Result<String, Error> {
|
||||
self.rt.block_on(self.api.list())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn add_tracker(&self, hash: &str, url: &str) -> Result<String, Error> {
|
||||
self.rt.block_on(self.api.add_tracker(hash, url))
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn get_trackers(&self, hash: &str) -> Result<String, Error> {
|
||||
self.rt.block_on(self.api.get_trackers(hash))
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn remove_tracker(&self, hash: &str, url: &str) -> Result<String, Error> {
|
||||
self.rt.block_on(self.api.remove_tracker(hash, url))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AsyncApiClient {
|
||||
pub raw_api: RawAsyncApiClient,
|
||||
}
|
||||
|
||||
impl AsyncApiClient {
|
||||
#[allow(dead_code)]
|
||||
pub async fn from_config(config: &Config) -> Result<AsyncApiClient, Error> {
|
||||
Self::new(&config.format_host(), &config.qbittorrent.login, &config.qbittorrent.password).await
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn new(host: &str, login: &str, password: &str) -> Result<AsyncApiClient, Error> {
|
||||
let api = UnauthenticatedRawAsyncApiClient::login(host, login, password).await?;
|
||||
|
||||
Ok(AsyncApiClient {
|
||||
raw_api: api,
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn add(&self, magnet: &str, paused: bool) -> Result<(), Error> {
|
||||
let res = self.raw_api.add(magnet, paused).await?;
|
||||
if res == "Ok." {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::message(res.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn get(&self, hash: &str) -> Result<Option<Torrent>, Error> {
|
||||
let res = self.raw_api.get(hash).await?;
|
||||
if res == "" {
|
||||
Ok(None)
|
||||
} else {
|
||||
// TODO: NOT OPTIMIZED AT ALL. API DOES NOT RETURN NAME/HASH OF TORRENT SO WE HAVE TO QUERY LIST...
|
||||
let list = self.list().await?;
|
||||
let filtered_list = list.into_iter().filter(|t| t.hash == hash).collect::<Vec<Torrent>>();
|
||||
let torrent = filtered_list.first()
|
||||
.unwrap_or_else(|| panic!("Torrent was 'get' but could not be found in 'list': {}", &hash));
|
||||
Ok(Some(torrent.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
/// This method only exists because qBittorrent API 'properties' endpoint does not return torrent name/hash
|
||||
/// so if you need to do a lot of 'get', please call 'list' once and use this method instead.
|
||||
pub async fn get_with_cached_list(&self, hash: &str, list: &TorrentList) -> Result<Option<Torrent>, Error> {
|
||||
let res = self.raw_api.get(hash).await?;
|
||||
if res == "" {
|
||||
Ok(None)
|
||||
} else {
|
||||
let filtered_list = list.clone().into_iter().filter(|t| t.hash == hash).collect::<Vec<Torrent>>();
|
||||
let torrent = filtered_list.first()
|
||||
.unwrap_or_else(|| panic!("Torrent was 'get' but could not be found in 'list': {}", &hash));
|
||||
Ok(Some(torrent.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn list(&self) -> Result<TorrentList, Error> {
|
||||
let res = self.raw_api.list().await?;
|
||||
let concrete: Vec<QBittorrentListTorrent> = serde_json::from_str(&res).context(DeserializeError)?;
|
||||
Ok(concrete.iter().map(|t| t.into_torrent()).collect())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn add_tracker(&self, hash: &str, url: &str) -> Result<(), Error> {
|
||||
let _ = self.raw_api.add_tracker(hash, url).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn get_trackers(&self, hash: &str) -> Result<Vec<TorrentTracker>, Error> {
|
||||
let res = self.raw_api.get_trackers(hash).await?;
|
||||
let concrete: Vec<TorrentTracker> = serde_json::from_str(&res).context(DeserializeError)?;
|
||||
let concrete_filter_dht = concrete.into_iter().filter(|t| t.is_tracker()).collect();
|
||||
Ok(concrete_filter_dht)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn remove_tracker(&self, hash: &str, url: &str) -> Result<(), Error> {
|
||||
let _ = self.raw_api.remove_tracker(hash, url).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ApiClient {
|
||||
pub rt: Runtime,
|
||||
pub api: AsyncApiClient,
|
||||
}
|
||||
|
||||
impl ApiClient {
|
||||
#[allow(dead_code)]
|
||||
pub fn from_config(config: &Config) -> Result<ApiClient, Error> {
|
||||
Self::new(&config.format_host(), &config.qbittorrent.login, &config.qbittorrent.password)
|
||||
}
|
||||
|
||||
/// Login into a qBittorrent backend and return a proper ApiClient instance
|
||||
#[allow(dead_code)]
|
||||
pub fn new(host: &str, login: &str, password: &str) -> Result<ApiClient, Error> {
|
||||
let rt = blocking_runtime().context(IOError)?;
|
||||
let api = rt.block_on(AsyncApiClient::new(host, login, password))?;
|
||||
Ok(ApiClient {
|
||||
rt,
|
||||
api,
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn add(&self, magnet: &str, paused: bool) -> Result<(), Error> {
|
||||
self.rt.block_on(self.api.add(magnet, paused))
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn get(&self, hash: &str) -> Result<Option<Torrent>, Error> {
|
||||
self.rt.block_on(self.api.get(hash))
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
// TODO: Workaround
|
||||
pub fn get_with_cached_list(&self, hash: &str, list: &TorrentList) -> Result<Option<Torrent>, Error> {
|
||||
self.rt.block_on(self.api.get_with_cached_list(hash, list))
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn list(&self) -> Result<TorrentList, Error> {
|
||||
self.rt.block_on(self.api.list())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn add_tracker(&self, hash: &str, url: &str) -> Result<(), Error> {
|
||||
self.rt.block_on(self.api.add_tracker(hash, url))
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn get_trackers(&self, hash: &str) -> Result<Vec<TorrentTracker>, Error> {
|
||||
self.rt.block_on(self.api.get_trackers(hash))
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn remove_tracker(&self, hash: &str, url: &str) -> Result<(), Error> {
|
||||
self.rt.block_on(self.api.remove_tracker(hash, url))
|
||||
}
|
||||
}
|
||||
mod raw_asynchronous;
|
||||
pub use raw_asynchronous::RawAsyncApiClient;
|
||||
mod asynchronous;
|
||||
pub use asynchronous::AsyncApiClient;
|
||||
mod synchronous;
|
||||
pub use synchronous::ApiClient;
|
||||
|
|
51
src/api/qbittorrent/raw_asynchronous.rs
Normal file
51
src/api/qbittorrent/raw_asynchronous.rs
Normal file
|
@ -0,0 +1,51 @@
|
|||
use snafu::prelude::*;
|
||||
use qbittorrent_web_api::Api;
|
||||
|
||||
use crate::error::{Error, InternalApiSnafu as ApiError};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RawAsyncApiClient {
|
||||
pub api: qbittorrent_web_api::api_impl::Authenticated,
|
||||
}
|
||||
|
||||
impl RawAsyncApiClient {
|
||||
pub async fn login(host: &str, login: &str, password: &str) -> Result<RawAsyncApiClient, Error> {
|
||||
Ok(RawAsyncApiClient {
|
||||
api: Api::login(host, login, password).await.context(ApiError)?,
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn add(&self, magnet: &str, paused: bool) -> Result<String, Error> {
|
||||
if paused {
|
||||
self.api.torrent_management().add(magnet).paused("true").send_raw().await.context(ApiError)
|
||||
} else {
|
||||
self.api.torrent_management().add(magnet).send_raw().await.context(ApiError)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn get(&self, hash: &str) -> Result<String, Error> {
|
||||
self.api.torrent_management().properties_raw(hash).await.context(ApiError)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn list(&self) -> Result<String, Error> {
|
||||
self.api.torrent_management().info().send_raw().await.context(ApiError)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn add_tracker(&self, hash: &str, url: &str) -> Result<String, Error> {
|
||||
self.api.torrent_management().add_trackers_raw(hash, url).await.context(ApiError)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn get_trackers(&self, hash: &str) -> Result<String, Error> {
|
||||
self.api.torrent_management().trackers_raw(hash).await.context(ApiError)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn remove_tracker(&self, hash: &str, url: &str) -> Result<String, Error> {
|
||||
self.api.torrent_management().remove_trackers_raw(hash, &vec!(url)).await.context(ApiError)
|
||||
}
|
||||
}
|
68
src/api/qbittorrent/synchronous.rs
Normal file
68
src/api/qbittorrent/synchronous.rs
Normal file
|
@ -0,0 +1,68 @@
|
|||
use snafu::prelude::*;
|
||||
use tokio::runtime::Runtime;
|
||||
|
||||
use crate::{Config, Error};
|
||||
use crate::api::{Torrent, TorrentList, TorrentTracker};
|
||||
use crate::api::qbittorrent::AsyncApiClient;
|
||||
use crate::error::ApiSnafu as IOError;
|
||||
use crate::utils::blocking_runtime;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ApiClient {
|
||||
pub rt: Runtime,
|
||||
pub api: AsyncApiClient,
|
||||
}
|
||||
|
||||
impl ApiClient {
|
||||
#[allow(dead_code)]
|
||||
pub fn from_config(config: &Config) -> Result<ApiClient, Error> {
|
||||
Self::new(&config.format_host(), &config.qbittorrent.login, &config.qbittorrent.password)
|
||||
}
|
||||
|
||||
/// Login into a qBittorrent backend and return a proper ApiClient instance
|
||||
#[allow(dead_code)]
|
||||
pub fn new(host: &str, login: &str, password: &str) -> Result<ApiClient, Error> {
|
||||
let rt = blocking_runtime().context(IOError)?;
|
||||
let api = rt.block_on(AsyncApiClient::new(host, login, password))?;
|
||||
Ok(ApiClient {
|
||||
rt,
|
||||
api,
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn add(&self, magnet: &str, paused: bool) -> Result<(), Error> {
|
||||
self.rt.block_on(self.api.add(magnet, paused))
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn get(&self, hash: &str) -> Result<Option<Torrent>, Error> {
|
||||
self.rt.block_on(self.api.get(hash))
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
// TODO: Workaround
|
||||
pub fn get_with_cached_list(&self, hash: &str, list: &TorrentList) -> Result<Option<Torrent>, Error> {
|
||||
self.rt.block_on(self.api.get_with_cached_list(hash, list))
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn list(&self) -> Result<TorrentList, Error> {
|
||||
self.rt.block_on(self.api.list())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn add_tracker(&self, hash: &str, url: &str) -> Result<(), Error> {
|
||||
self.rt.block_on(self.api.add_tracker(hash, url))
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn get_trackers(&self, hash: &str) -> Result<Vec<TorrentTracker>, Error> {
|
||||
self.rt.block_on(self.api.get_trackers(hash))
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn remove_tracker(&self, hash: &str, url: &str) -> Result<(), Error> {
|
||||
self.rt.block_on(self.api.remove_tracker(hash, url))
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
use snafu::prelude::*;
|
||||
use tokio::runtime::{Builder,Runtime};
|
||||
|
||||
use imdl::infohash::Infohash;
|
||||
use imdl::input::Input;
|
||||
|
@ -84,3 +85,9 @@ pub fn find_free_port() -> u16 {
|
|||
let bind = TcpListener::bind("127.0.0.1:0").unwrap();
|
||||
bind.local_addr().unwrap().port()
|
||||
}
|
||||
|
||||
pub fn blocking_runtime() -> std::io::Result<Runtime> {
|
||||
Builder::new_current_thread()
|
||||
.enable_all()
|
||||
.build()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user