diff --git a/Cargo.toml b/Cargo.toml index 42bc89d..493059a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.1" authors = ["red "] edition = "2018" repository = "https://github.com/j0rsa/transmission-rpc" -license-file = "LICENSE" +license = "MIT" readme = "README.md" description = "Transmission JRPC client" keywords = ["transmission", "torrent", "jrpc"] diff --git a/README.md b/README.md index 01e75e5..5c6b1ad 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,16 @@ spec: https://github.com/transmission/transmission/blob/master/extras/rpc-spec.t Supported Methods: +Torrent Actions: + +- [X] torrent-start +- [X] torrent-stop +- [X] torrent-start-now +- [X] torrent-verify +- [X] torrent-reannounce + +Torrent modificators: + - [ ] torrent-set - [X] torrent-get - [ ] torrent-add diff --git a/examples/torrent-action.rs b/examples/torrent-action.rs new file mode 100644 index 0000000..f625baf --- /dev/null +++ b/examples/torrent-action.rs @@ -0,0 +1,22 @@ +extern crate transmission_rpc; + +use std::env; +use dotenv::dotenv; +use transmission_rpc::TransClient; +use transmission_rpc::types::{Result, RpcResponse, BasicAuth}; +use transmission_rpc::types::{TorrentAction, Nothing}; + +#[tokio::main] +async fn main() -> Result<()> { + dotenv().ok(); + env_logger::init(); + let url= env::var("TURL")?; + let basic_auth = BasicAuth{user: env::var("TUSER")?, password: env::var("TPWD")?}; + let client = TransClient::with_auth(&url, basic_auth); + let res1: RpcResponse = client.torrent_action(TorrentAction::Start, vec![1]).await?; + println!("Start result: {:?}", &res1.is_ok()); + let res2: RpcResponse = client.torrent_action(TorrentAction::Stop, vec![1]).await?; + println!("Stop result: {:?}", &res2.is_ok()); + + Ok(()) +} \ No newline at end of file diff --git a/examples/torrent-get.rs b/examples/torrent-get.rs index eff5d58..0c6d4ef 100644 --- a/examples/torrent-get.rs +++ b/examples/torrent-get.rs @@ -13,8 +13,8 @@ async fn main() -> Result<()> { let url= env::var("TURL")?; let basic_auth = BasicAuth{user: env::var("TUSER")?, password: env::var("TPWD")?}; let client = TransClient::with_auth(&url, basic_auth); - let res: RpcResponse> = client.torrent_get(vec![TorrentGetField::ID, TorrentGetField::NAME]).await?; - let names: Vec<&String> = res.arguments.torrents.iter().map(|it| it.clone().name.as_ref().unwrap()).collect(); + let res: RpcResponse> = client.torrent_get(vec![TorrentGetField::Id, TorrentGetField::Name]).await?; + let names: Vec<&String> = res.arguments.torrents.iter().map(|it| it.name.as_ref().unwrap()).collect(); println!("{:#?}", names); Ok(()) } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 8e3808c..a3c0bb8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,9 +12,10 @@ use reqwest::header::CONTENT_TYPE; pub mod types; use types::BasicAuth; -use types::{Result, RpcResponse, RpcResponseArgument, RpcRequest}; +use types::{Result, RpcResponse, RpcResponseArgument, RpcRequest, Nothing}; use types::SessionGet; use types::{TorrentGetField, Torrents, Torrent}; +use types::TorrentAction; pub struct TransClient { url: String, @@ -73,6 +74,10 @@ impl TransClient { self.call(RpcRequest::torrent_get(fields)).await } + pub async fn torrent_action(&self, action: TorrentAction, ids: Vec) -> Result> { + self.call(RpcRequest::torrent_action(action, ids)).await + } + async fn call (&self, request: RpcRequest) -> Result> where RS : RpcResponseArgument + DeserializeOwned + std::fmt::Debug { diff --git a/src/types/mod.rs b/src/types/mod.rs index 1a7a2ba..1a11514 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -13,9 +13,11 @@ pub struct BasicAuth { pub(crate) use self::request::RpcRequest; pub use self::request::ArgumentFields; pub use self::request::TorrentGetField; +pub use self::request::TorrentAction; pub use self::response::RpcResponse; pub(crate) use self::response::RpcResponseArgument; pub use self::response::SessionGet; pub use self::response::Torrents; -pub use self::response::Torrent; \ No newline at end of file +pub use self::response::Torrent; +pub use self::response::Nothing; \ No newline at end of file diff --git a/src/types/request.rs b/src/types/request.rs index 3a608ff..0df85e9 100644 --- a/src/types/request.rs +++ b/src/types/request.rs @@ -4,9 +4,7 @@ use serde::Serialize; pub struct RpcRequest { method: String, #[serde(skip_serializing_if="Option::is_none")] - arguments: Option>, - #[serde(skip_serializing_if="Option::is_none")] - ids: Option, + arguments: Option, } impl RpcRequest { @@ -14,7 +12,6 @@ impl RpcRequest { RpcRequest { method: String::from("session-get"), arguments: None, - ids: None, } } @@ -22,11 +19,16 @@ impl RpcRequest { let string_fields = fields.iter().map(|f| f.to_str()).collect(); RpcRequest { method: String::from("torrent-get"), - arguments: Some (Fields { fields: string_fields }), - ids: None, + arguments: Some (Args { fields: Some(string_fields), ids: None }), } } + pub fn torrent_action(action: TorrentAction, ids: Vec) -> RpcRequest { + RpcRequest { + method: action.to_str(), + arguments: Some (Args { fields: None, ids: Some(ids) }), + } + } } @@ -34,72 +36,95 @@ pub trait ArgumentFields {} impl ArgumentFields for TorrentGetField{} #[derive(Serialize, Debug, RustcEncodable)] -struct Fields { - fields: Vec +struct Args { + #[serde(skip_serializing_if="Option::is_none")] + fields: Option>, + #[serde(skip_serializing_if="Option::is_none")] + ids: Option> } pub enum TorrentGetField { - ID, - ADDEDDATE, - NAME, - TOTALSIZE, - ERROR, - ERRORSTRING, - ETA, - ISFINISHED, - ISSTALLED, - LEFTUNTILDONE, - METADATAPERCENTCOMPLETE, - PEERSCONNECTED, - PEERSGETTINGFROMUS, - PEERSSENDINGTOUS, - PERCENTDONE, - QUEUEPOSITION, - RATEDOWNLOAD, - RATEUPLOAD, - RECHECKPROGRESS, - SEEDRATIOMODE, - SEEDRATIOLIMIT, - SIZEWHENDONE, - STATUS, - TRACKERS, - DOWNLOADDIR, - UPLOADEDEVER, - UPLOADRATIO, - WEBSEEDSSENDINGTOUS, + Id, + Addeddate, + Name, + Totalsize, + Error, + Errorstring, + Eta, + Isfinished, + Isstalled, + Leftuntildone, + Metadatapercentcomplete, + Peersconnected, + Peersgettingfromus, + Peerssendingtous, + Percentdone, + Queueposition, + Ratedownload, + Rateupload, + Recheckprogress, + Seedratiomode, + Seedratiolimit, + Sizewhendone, + Status, + Trackers, + Downloaddir, + Uploadedever, + Uploadratio, + Webseedssendingtous, } impl TorrentGetField { pub fn to_str(&self) -> String { match self { - TorrentGetField::ID => "id", - TorrentGetField::ADDEDDATE => "addedDate", - TorrentGetField::NAME => "name", - TorrentGetField::TOTALSIZE => "totalSize", - TorrentGetField::ERROR => "error", - TorrentGetField::ERRORSTRING => "errorString", - TorrentGetField::ETA => "eta", - TorrentGetField::ISFINISHED => "isFinished", - TorrentGetField::ISSTALLED => "isStalled", - TorrentGetField::LEFTUNTILDONE => "leftUntilDone", - TorrentGetField::METADATAPERCENTCOMPLETE => "metadataPercentComplete", - TorrentGetField::PEERSCONNECTED => "peersConnected", - TorrentGetField::PEERSGETTINGFROMUS => "peersGettingFromUs", - TorrentGetField::PEERSSENDINGTOUS => "peersSendingToUs", - TorrentGetField::PERCENTDONE => "percentDone", - TorrentGetField::QUEUEPOSITION => "queuePosition", - TorrentGetField::RATEDOWNLOAD => "rateDownload", - TorrentGetField::RATEUPLOAD => "rateUpload", - TorrentGetField::RECHECKPROGRESS => "recheckProgress", - TorrentGetField::SEEDRATIOMODE => "seedRatioMode", - TorrentGetField::SEEDRATIOLIMIT => "seedRatioLimit", - TorrentGetField::SIZEWHENDONE => "sizeWhenDone", - TorrentGetField::STATUS => "status", - TorrentGetField::TRACKERS => "trackers", - TorrentGetField::DOWNLOADDIR => "downloadDir", - TorrentGetField::UPLOADEDEVER => "uploadedEver", - TorrentGetField::UPLOADRATIO => "uploadRatio", - TorrentGetField::WEBSEEDSSENDINGTOUS => "webseedsSendingToUs", + TorrentGetField::Id => "id", + TorrentGetField::Addeddate => "addedDate", + TorrentGetField::Name => "name", + TorrentGetField::Totalsize => "totalSize", + TorrentGetField::Error => "error", + TorrentGetField::Errorstring => "errorString", + TorrentGetField::Eta => "eta", + TorrentGetField::Isfinished => "isFinished", + TorrentGetField::Isstalled => "isStalled", + TorrentGetField::Leftuntildone => "leftUntilDone", + TorrentGetField::Metadatapercentcomplete => "metadataPercentComplete", + TorrentGetField::Peersconnected => "peersConnected", + TorrentGetField::Peersgettingfromus => "peersGettingFromUs", + TorrentGetField::Peerssendingtous => "peersSendingToUs", + TorrentGetField::Percentdone => "percentDone", + TorrentGetField::Queueposition => "queuePosition", + TorrentGetField::Ratedownload => "rateDownload", + TorrentGetField::Rateupload => "rateUpload", + TorrentGetField::Recheckprogress => "recheckProgress", + TorrentGetField::Seedratiomode => "seedRatioMode", + TorrentGetField::Seedratiolimit => "seedRatioLimit", + TorrentGetField::Sizewhendone => "sizeWhenDone", + TorrentGetField::Status => "status", + TorrentGetField::Trackers => "trackers", + TorrentGetField::Downloaddir => "downloadDir", + TorrentGetField::Uploadedever => "uploadedEver", + TorrentGetField::Uploadratio => "uploadRatio", + TorrentGetField::Webseedssendingtous => "webseedsSendingToUs", }.to_string() } -} \ No newline at end of file +} + +pub enum TorrentAction { + Start, + Stop, + StartNow, + Verify, + Reannounce, +} + +impl TorrentAction { + pub fn to_str(&self) -> String { + match self { + TorrentAction::Start => "torrent-start", + TorrentAction::Stop => "torrent-stop", + TorrentAction::StartNow => "torrent-start-now", + TorrentAction::Verify => "torrent-verify", + TorrentAction::Reannounce => "torrent-reannounce", + }.to_string() + } +} diff --git a/src/types/response.rs b/src/types/response.rs index b1f9e47..fe0b285 100644 --- a/src/types/response.rs +++ b/src/types/response.rs @@ -85,4 +85,8 @@ pub struct Torrents { pub struct Trackers { pub id: i32, pub announce: String, -} \ No newline at end of file +} + +#[derive(Deserialize, Debug, RustcEncodable)] +pub struct Nothing{} +impl RpcResponseArgument for Nothing {} \ No newline at end of file