added torrent actions

This commit is contained in:
red 2020-04-21 19:12:29 +02:00
parent 56e454915a
commit f2420e876a
8 changed files with 139 additions and 71 deletions

View File

@ -4,7 +4,7 @@ version = "0.1.1"
authors = ["red <red.avtovo@gmail.com>"] authors = ["red <red.avtovo@gmail.com>"]
edition = "2018" edition = "2018"
repository = "https://github.com/j0rsa/transmission-rpc" repository = "https://github.com/j0rsa/transmission-rpc"
license-file = "LICENSE" license = "MIT"
readme = "README.md" readme = "README.md"
description = "Transmission JRPC client" description = "Transmission JRPC client"
keywords = ["transmission", "torrent", "jrpc"] keywords = ["transmission", "torrent", "jrpc"]

View File

@ -4,6 +4,16 @@ spec: https://github.com/transmission/transmission/blob/master/extras/rpc-spec.t
Supported Methods: Supported Methods:
Torrent Actions:
- [X] torrent-start
- [X] torrent-stop
- [X] torrent-start-now
- [X] torrent-verify
- [X] torrent-reannounce
Torrent modificators:
- [ ] torrent-set - [ ] torrent-set
- [X] torrent-get - [X] torrent-get
- [ ] torrent-add - [ ] torrent-add

View File

@ -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<Nothing> = client.torrent_action(TorrentAction::Start, vec![1]).await?;
println!("Start result: {:?}", &res1.is_ok());
let res2: RpcResponse<Nothing> = client.torrent_action(TorrentAction::Stop, vec![1]).await?;
println!("Stop result: {:?}", &res2.is_ok());
Ok(())
}

View File

@ -13,8 +13,8 @@ async fn main() -> Result<()> {
let url= env::var("TURL")?; let url= env::var("TURL")?;
let basic_auth = BasicAuth{user: env::var("TUSER")?, password: env::var("TPWD")?}; let basic_auth = BasicAuth{user: env::var("TUSER")?, password: env::var("TPWD")?};
let client = TransClient::with_auth(&url, basic_auth); let client = TransClient::with_auth(&url, basic_auth);
let res: RpcResponse<Torrents<Torrent>> = client.torrent_get(vec![TorrentGetField::ID, TorrentGetField::NAME]).await?; let res: RpcResponse<Torrents<Torrent>> = 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 names: Vec<&String> = res.arguments.torrents.iter().map(|it| it.name.as_ref().unwrap()).collect();
println!("{:#?}", names); println!("{:#?}", names);
Ok(()) Ok(())
} }

View File

@ -12,9 +12,10 @@ use reqwest::header::CONTENT_TYPE;
pub mod types; pub mod types;
use types::BasicAuth; use types::BasicAuth;
use types::{Result, RpcResponse, RpcResponseArgument, RpcRequest}; use types::{Result, RpcResponse, RpcResponseArgument, RpcRequest, Nothing};
use types::SessionGet; use types::SessionGet;
use types::{TorrentGetField, Torrents, Torrent}; use types::{TorrentGetField, Torrents, Torrent};
use types::TorrentAction;
pub struct TransClient { pub struct TransClient {
url: String, url: String,
@ -73,6 +74,10 @@ impl TransClient {
self.call(RpcRequest::torrent_get(fields)).await self.call(RpcRequest::torrent_get(fields)).await
} }
pub async fn torrent_action(&self, action: TorrentAction, ids: Vec<i64>) -> Result<RpcResponse<Nothing>> {
self.call(RpcRequest::torrent_action(action, ids)).await
}
async fn call<RS> (&self, request: RpcRequest) -> Result<RpcResponse<RS>> async fn call<RS> (&self, request: RpcRequest) -> Result<RpcResponse<RS>>
where RS : RpcResponseArgument + DeserializeOwned + std::fmt::Debug where RS : RpcResponseArgument + DeserializeOwned + std::fmt::Debug
{ {

View File

@ -13,9 +13,11 @@ pub struct BasicAuth {
pub(crate) use self::request::RpcRequest; pub(crate) use self::request::RpcRequest;
pub use self::request::ArgumentFields; pub use self::request::ArgumentFields;
pub use self::request::TorrentGetField; pub use self::request::TorrentGetField;
pub use self::request::TorrentAction;
pub use self::response::RpcResponse; pub use self::response::RpcResponse;
pub(crate) use self::response::RpcResponseArgument; pub(crate) use self::response::RpcResponseArgument;
pub use self::response::SessionGet; pub use self::response::SessionGet;
pub use self::response::Torrents; pub use self::response::Torrents;
pub use self::response::Torrent; pub use self::response::Torrent;
pub use self::response::Nothing;

View File

@ -4,9 +4,7 @@ use serde::Serialize;
pub struct RpcRequest { pub struct RpcRequest {
method: String, method: String,
#[serde(skip_serializing_if="Option::is_none")] #[serde(skip_serializing_if="Option::is_none")]
arguments: Option<Fields<String>>, arguments: Option<Args>,
#[serde(skip_serializing_if="Option::is_none")]
ids: Option<String>,
} }
impl RpcRequest { impl RpcRequest {
@ -14,7 +12,6 @@ impl RpcRequest {
RpcRequest { RpcRequest {
method: String::from("session-get"), method: String::from("session-get"),
arguments: None, arguments: None,
ids: None,
} }
} }
@ -22,11 +19,16 @@ impl RpcRequest {
let string_fields = fields.iter().map(|f| f.to_str()).collect(); let string_fields = fields.iter().map(|f| f.to_str()).collect();
RpcRequest { RpcRequest {
method: String::from("torrent-get"), method: String::from("torrent-get"),
arguments: Some (Fields { fields: string_fields }), arguments: Some (Args { fields: Some(string_fields), ids: None }),
ids: None,
} }
} }
pub fn torrent_action(action: TorrentAction, ids: Vec<i64>) -> 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{} impl ArgumentFields for TorrentGetField{}
#[derive(Serialize, Debug, RustcEncodable)] #[derive(Serialize, Debug, RustcEncodable)]
struct Fields<T> { struct Args {
fields: Vec<T> #[serde(skip_serializing_if="Option::is_none")]
fields: Option<Vec<String>>,
#[serde(skip_serializing_if="Option::is_none")]
ids: Option<Vec<i64>>
} }
pub enum TorrentGetField { pub enum TorrentGetField {
ID, Id,
ADDEDDATE, Addeddate,
NAME, Name,
TOTALSIZE, Totalsize,
ERROR, Error,
ERRORSTRING, Errorstring,
ETA, Eta,
ISFINISHED, Isfinished,
ISSTALLED, Isstalled,
LEFTUNTILDONE, Leftuntildone,
METADATAPERCENTCOMPLETE, Metadatapercentcomplete,
PEERSCONNECTED, Peersconnected,
PEERSGETTINGFROMUS, Peersgettingfromus,
PEERSSENDINGTOUS, Peerssendingtous,
PERCENTDONE, Percentdone,
QUEUEPOSITION, Queueposition,
RATEDOWNLOAD, Ratedownload,
RATEUPLOAD, Rateupload,
RECHECKPROGRESS, Recheckprogress,
SEEDRATIOMODE, Seedratiomode,
SEEDRATIOLIMIT, Seedratiolimit,
SIZEWHENDONE, Sizewhendone,
STATUS, Status,
TRACKERS, Trackers,
DOWNLOADDIR, Downloaddir,
UPLOADEDEVER, Uploadedever,
UPLOADRATIO, Uploadratio,
WEBSEEDSSENDINGTOUS, Webseedssendingtous,
} }
impl TorrentGetField { impl TorrentGetField {
pub fn to_str(&self) -> String { pub fn to_str(&self) -> String {
match self { match self {
TorrentGetField::ID => "id", TorrentGetField::Id => "id",
TorrentGetField::ADDEDDATE => "addedDate", TorrentGetField::Addeddate => "addedDate",
TorrentGetField::NAME => "name", TorrentGetField::Name => "name",
TorrentGetField::TOTALSIZE => "totalSize", TorrentGetField::Totalsize => "totalSize",
TorrentGetField::ERROR => "error", TorrentGetField::Error => "error",
TorrentGetField::ERRORSTRING => "errorString", TorrentGetField::Errorstring => "errorString",
TorrentGetField::ETA => "eta", TorrentGetField::Eta => "eta",
TorrentGetField::ISFINISHED => "isFinished", TorrentGetField::Isfinished => "isFinished",
TorrentGetField::ISSTALLED => "isStalled", TorrentGetField::Isstalled => "isStalled",
TorrentGetField::LEFTUNTILDONE => "leftUntilDone", TorrentGetField::Leftuntildone => "leftUntilDone",
TorrentGetField::METADATAPERCENTCOMPLETE => "metadataPercentComplete", TorrentGetField::Metadatapercentcomplete => "metadataPercentComplete",
TorrentGetField::PEERSCONNECTED => "peersConnected", TorrentGetField::Peersconnected => "peersConnected",
TorrentGetField::PEERSGETTINGFROMUS => "peersGettingFromUs", TorrentGetField::Peersgettingfromus => "peersGettingFromUs",
TorrentGetField::PEERSSENDINGTOUS => "peersSendingToUs", TorrentGetField::Peerssendingtous => "peersSendingToUs",
TorrentGetField::PERCENTDONE => "percentDone", TorrentGetField::Percentdone => "percentDone",
TorrentGetField::QUEUEPOSITION => "queuePosition", TorrentGetField::Queueposition => "queuePosition",
TorrentGetField::RATEDOWNLOAD => "rateDownload", TorrentGetField::Ratedownload => "rateDownload",
TorrentGetField::RATEUPLOAD => "rateUpload", TorrentGetField::Rateupload => "rateUpload",
TorrentGetField::RECHECKPROGRESS => "recheckProgress", TorrentGetField::Recheckprogress => "recheckProgress",
TorrentGetField::SEEDRATIOMODE => "seedRatioMode", TorrentGetField::Seedratiomode => "seedRatioMode",
TorrentGetField::SEEDRATIOLIMIT => "seedRatioLimit", TorrentGetField::Seedratiolimit => "seedRatioLimit",
TorrentGetField::SIZEWHENDONE => "sizeWhenDone", TorrentGetField::Sizewhendone => "sizeWhenDone",
TorrentGetField::STATUS => "status", TorrentGetField::Status => "status",
TorrentGetField::TRACKERS => "trackers", TorrentGetField::Trackers => "trackers",
TorrentGetField::DOWNLOADDIR => "downloadDir", TorrentGetField::Downloaddir => "downloadDir",
TorrentGetField::UPLOADEDEVER => "uploadedEver", TorrentGetField::Uploadedever => "uploadedEver",
TorrentGetField::UPLOADRATIO => "uploadRatio", TorrentGetField::Uploadratio => "uploadRatio",
TorrentGetField::WEBSEEDSSENDINGTOUS => "webseedsSendingToUs", TorrentGetField::Webseedssendingtous => "webseedsSendingToUs",
}.to_string() }.to_string()
} }
} }
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()
}
}

View File

@ -85,4 +85,8 @@ pub struct Torrents<T> {
pub struct Trackers { pub struct Trackers {
pub id: i32, pub id: i32,
pub announce: String, pub announce: String,
} }
#[derive(Deserialize, Debug, RustcEncodable)]
pub struct Nothing{}
impl RpcResponseArgument for Nothing {}