aria2_rs_yet/
call.rs

1use serde::ser::{SerializeSeq, Serializer};
2use serde_with::{serde_as, DisplayFromStr};
3
4use crate::options::Aria2Options;
5
6pub trait Call {
7    type Response: serde::de::DeserializeOwned;
8
9    fn method(&self) -> &'static str;
10    fn serialize_params<S: SerializeSeq>(&self, _serializer: &mut S) -> Result<(), S::Error> {
11        Ok(())
12    }
13    fn to_params(self, token: Option<&str>) -> Option<Aria2Params<'_, Self>>
14    where
15        Self: Sized,
16    {
17        Some(Aria2Params::new(token, self))
18    }
19}
20
21macro_rules! option_element {
22    ($opt: expr, $serializer: expr) => {
23        if let Some(ref value) = $opt {
24            $serializer.serialize_element(value)?;
25        }
26    };
27}
28
29/// https://aria2.github.io/manual/en/html/aria2c.html#rpc-authorization-secret-token
30#[derive(Debug)]
31pub struct Aria2Params<'a, T> {
32    token: Option<&'a str>,
33    params: T,
34}
35
36impl<'a, T> Aria2Params<'a, T> {
37    /// token with prefix
38    pub fn new(token: Option<&'a str>, params: T) -> Self {
39        Self { token, params }
40    }
41}
42
43impl<T> serde::Serialize for Aria2Params<'_, T>
44where
45    T: Call,
46{
47    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
48    where
49        S: Serializer,
50    {
51        let mut seq = serializer.serialize_seq(Some(2))?;
52        option_element!(self.token, seq);
53        self.params.serialize_params(&mut seq)?;
54        seq.end()
55    }
56}
57
58#[derive(Debug)]
59pub struct SystemListMethods;
60impl Call for SystemListMethods {
61    type Response = Vec<String>;
62
63    fn method(&self) -> &'static str {
64        "system.listMethods"
65    }
66
67    fn to_params(self, _: Option<&str>) -> Option<Aria2Params<'_, Self>>
68    where
69        Self: Sized,
70    {
71        None
72    }
73}
74
75#[derive(Debug)]
76pub struct AddUri {
77    pub uris: Vec<String>,
78    pub options: Option<Aria2Options>,
79    pub position: Option<i32>,
80}
81
82impl AddUri {
83    pub fn new<S: Into<String>>(
84        uris: Vec<S>,
85        options: Option<Aria2Options>,
86        position: Option<i32>,
87    ) -> Self {
88        Self::uris(uris).options(options).position(position)
89    }
90
91    pub fn uris<S: Into<String>>(uris: Vec<S>) -> Self {
92        Self {
93            uris: uris.into_iter().map(|s| s.into()).collect(),
94            options: None,
95            position: None,
96        }
97    }
98
99    pub fn options(mut self, options: Option<Aria2Options>) -> Self {
100        self.options = options;
101        self
102    }
103
104    pub fn position(mut self, position: Option<i32>) -> Self {
105        self.position = position;
106        self
107    }
108}
109
110impl Call for AddUri {
111    type Response = GidReply;
112
113    fn method(&self) -> &'static str {
114        "aria2.addUri"
115    }
116
117    fn serialize_params<S: SerializeSeq>(&self, serializer: &mut S) -> Result<(), S::Error> {
118        serializer.serialize_element(&self.uris)?;
119        option_element!(self.options, serializer);
120        option_element!(self.position, serializer);
121        Ok(())
122    }
123}
124
125#[derive(serde::Deserialize, Debug, Clone)]
126#[serde(transparent)]
127pub struct GidReply(pub String);
128
129impl From<GidReply> for String {
130    fn from(gid: GidReply) -> Self {
131        gid.0
132    }
133}
134
135#[derive(Debug)]
136pub struct GetVersion;
137impl Call for GetVersion {
138    type Response = VersionReply;
139
140    fn method(&self) -> &'static str {
141        "aria2.getVersion"
142    }
143}
144
145#[derive(serde::Deserialize, Debug, Clone)]
146pub struct VersionReply {
147    pub version: String,
148    #[serde(rename = "enabledFeatures")]
149    pub enabled_features: Vec<String>,
150}
151
152#[derive(Debug, serde::Serialize, PartialEq, Eq, Hash)]
153#[serde(rename_all = "camelCase")]
154pub enum TellStatusField {
155    Gid,
156    Status,
157    TotalLength,
158    CompletedLength,
159    UploadedLength,
160    BitField,
161    DownloadSpeed,
162    UploadSpeed,
163    InfoHash,
164    NumSeeders,
165    Seeder,
166    PieceLength,
167    NumPieces,
168    Connections,
169    ErrorCode,
170    ErrorMessage,
171    FollowedBy,
172    Following,
173    BelongsTo,
174    Dir,
175    Files,
176    // bt nested fields not supported now
177    // Bittorrent,
178    VerifiedLength,
179    VeriyIntegrityPending,
180}
181
182impl TryFrom<&str> for TellStatusField {
183    type Error = &'static str;
184
185    fn try_from(value: &str) -> Result<Self, Self::Error> {
186        match value {
187            "gid" => Ok(Self::Gid),
188            "status" => Ok(Self::Status),
189            "totalLength" => Ok(Self::TotalLength),
190            "completedLength" => Ok(Self::CompletedLength),
191            "uploadedLength" => Ok(Self::UploadedLength),
192            "bitField" => Ok(Self::BitField),
193            "downloadSpeed" => Ok(Self::DownloadSpeed),
194            "uploadSpeed" => Ok(Self::UploadSpeed),
195            "infoHash" => Ok(Self::InfoHash),
196            "numSeeders" => Ok(Self::NumSeeders),
197            "seeder" => Ok(Self::Seeder),
198            "pieceLength" => Ok(Self::PieceLength),
199            "numPieces" => Ok(Self::NumPieces),
200            "connections" => Ok(Self::Connections),
201            "errorCode" => Ok(Self::ErrorCode),
202            "errorMessage" => Ok(Self::ErrorMessage),
203            "followedBy" => Ok(Self::FollowedBy),
204            "following" => Ok(Self::Following),
205            "belongsTo" => Ok(Self::BelongsTo),
206            "dir" => Ok(Self::Dir),
207            "files" => Ok(Self::Files),
208            // Bittorrent
209            "verifiedLength" => Ok(Self::VerifiedLength),
210            "veriyIntegrityPending" => Ok(Self::VeriyIntegrityPending),
211            _ => Err("Invalid TellStatusField"),
212        }
213    }
214}
215
216#[derive(Debug, Clone, Copy, PartialEq, serde::Deserialize)]
217#[serde(rename_all = "lowercase")]
218pub enum TaskStatus {
219    Active,
220    Waiting,
221    Paused,
222    Error,
223    Complete,
224    Removed,
225}
226
227/// https://aria2.github.io/manual/en/html/aria2c.html#aria2.tellStatus
228#[derive(Debug)]
229pub struct TellStatus {
230    pub gid: String,
231    pub keys: Option<std::collections::HashSet<TellStatusField>>,
232}
233
234macro_rules! tell_star {
235    ($name: ident) => {
236        impl $name {
237            /// replace all fields wanted to be returned
238            pub fn keys<I, F>(mut self, keys: Option<I>) -> Result<Self, F::Error>
239            where
240                I: IntoIterator<Item = F>,
241                F: TryInto<TellStatusField, Error = &'static str>,
242            {
243                self.keys = None;
244
245                if let Some(keys) = keys {
246                    let mut temp = std::collections::HashSet::new();
247                    for field in keys.into_iter() {
248                        match field.try_into() {
249                            Ok(f) => {
250                                temp.insert(f);
251                            }
252                            Err(e) => return Err(e),
253                        }
254                    }
255                    self.keys = Some(temp);
256                }
257                Ok(self)
258            }
259
260            /// add key
261            pub fn key<F>(self, key: F) -> Result<Self, F::Error>
262            where
263                F: TryInto<TellStatusField, Error = &'static str>,
264            {
265                let field = key.try_into()?;
266                Ok(self.field(field))
267            }
268
269            pub fn field<F>(mut self, field: F) -> Self
270            where
271                F: Into<TellStatusField>,
272            {
273                if let Some(ref mut keys) = self.keys {
274                    keys.insert(field.into());
275                } else {
276                    let mut keys = std::collections::HashSet::new();
277                    keys.insert(field.into());
278                    self.keys = Some(keys);
279                }
280                self
281            }
282
283            pub fn fields<I, F>(mut self, fields: Option<I>) -> Self
284            where
285                I: IntoIterator<Item = F>,
286                F: Into<TellStatusField>,
287            {
288                self.keys = None;
289                if let Some(fields) = fields {
290                    let mut keys = std::collections::HashSet::new();
291                    for field in fields.into_iter() {
292                        keys.insert(field.into());
293                    }
294                    self.keys = Some(keys);
295                }
296                self
297            }
298        }
299    };
300}
301
302impl TellStatus {
303    /// create a new TellStatus
304    pub fn new<G: Into<String>>(gid: G) -> Self {
305        Self {
306            gid: gid.into(),
307            keys: None,
308        }
309    }
310
311    pub fn new_with_fields<G, I, F>(gid: G, fields: I) -> Self
312    where
313        G: Into<String>,
314        I: IntoIterator<Item = F>,
315        F: Into<TellStatusField>,
316    {
317        Self::new(gid).fields(Some(fields))
318    }
319}
320
321tell_star!(TellStatus);
322
323#[serde_as]
324#[derive(Debug, Clone, serde::Deserialize)]
325#[serde(rename_all = "camelCase")]
326pub struct TellStatusReply {
327    pub gid: Option<String>,
328    pub status: Option<TaskStatus>,
329    #[serde_as(as = "Option<DisplayFromStr>")]
330    pub total_length: Option<u64>,
331    #[serde_as(as = "Option<DisplayFromStr>")]
332    pub completed_length: Option<u64>,
333    #[serde_as(as = "Option<DisplayFromStr>")]
334    pub upload_length: Option<u64>,
335    pub bitfield: Option<String>,
336    #[serde_as(as = "Option<DisplayFromStr>")]
337    pub download_speed: Option<u64>,
338    #[serde_as(as = "Option<DisplayFromStr>")]
339    pub upload_speed: Option<u64>,
340    #[serde_as(as = "Option<DisplayFromStr>")]
341    pub piece_length: Option<u64>,
342    #[serde_as(as = "Option<DisplayFromStr>")]
343    pub num_pieces: Option<u64>,
344    #[serde_as(as = "Option<DisplayFromStr>")]
345    pub connections: Option<u64>,
346    pub dir: Option<String>,
347    pub files: Option<Vec<TellStatusReplyFile>>,
348}
349
350#[serde_as]
351#[derive(Debug, Clone, serde::Deserialize)]
352#[serde(rename_all = "camelCase")]
353pub struct TellStatusReplyFile {
354    pub index: String,
355    #[serde_as(as = "DisplayFromStr")]
356    pub length: u64,
357    #[serde_as(as = "DisplayFromStr")]
358    pub completed_length: u64,
359    pub path: String,
360    #[serde_as(as = "DisplayFromStr")]
361    pub selected: bool,
362    pub uris: Vec<TellStatusReplyUri>,
363}
364
365#[derive(Debug, Clone, Copy, PartialEq, serde::Deserialize)]
366#[serde(rename_all = "lowercase")]
367pub enum URIStatus {
368    Used,
369    Waiting,
370}
371#[derive(Debug, Clone, serde::Deserialize)]
372#[serde(rename_all = "camelCase")]
373pub struct TellStatusReplyUri {
374    pub status: URIStatus,
375    pub uri: String,
376}
377
378impl Call for TellStatus {
379    type Response = TellStatusReply;
380
381    fn method(&self) -> &'static str {
382        "aria2.tellStatus"
383    }
384
385    fn serialize_params<S: SerializeSeq>(&self, serializer: &mut S) -> Result<(), S::Error> {
386        serializer.serialize_element(&self.gid)?;
387        option_element!(self.keys, serializer);
388        Ok(())
389    }
390}
391
392#[derive(Debug)]
393pub struct TellActive {
394    keys: Option<std::collections::HashSet<TellStatusField>>,
395}
396
397impl TellActive {
398    pub fn new() -> Self {
399        Self { keys: None }
400    }
401
402    pub fn new_with_fields<I, F>(fields: I) -> Self
403    where
404        I: IntoIterator<Item = F>,
405        F: Into<TellStatusField>,
406    {
407        Self::new().fields(Some(fields))
408    }
409}
410
411tell_star!(TellActive);
412
413
414impl Call for TellActive {
415    type Response = Vec<TellStatusReply>;
416
417    fn method(&self) -> &'static str {
418        "aria2.tellActive"
419    }
420
421    fn serialize_params<S: SerializeSeq>(&self, serializer: &mut S) -> Result<(), S::Error> {
422        option_element!(self.keys, serializer);
423        Ok(())
424    }
425}
426
427#[derive(Debug)]
428pub struct TellWaiting {
429    ///If offset is a positive integer, this method returns downloads in the range of [offset, offset + num).
430    /// 
431    /// offset can be a negative integer. offset == -1 points last download in the waiting queue and offset == -2 points the download before the last download, and so on.
432    /// Downloads in the response are in reversed order then.
433    pub offset: i32,
434    pub num: i32,
435    keys: Option<std::collections::HashSet<TellStatusField>>,
436}
437impl TellWaiting {
438    pub fn new(offset: i32, num: i32) -> Self {
439        Self {
440            offset,
441            num,
442            keys: None,
443        }
444    }
445
446    pub fn new_with_fields<I, F>(offset: i32, num: i32, fields: I) -> Self
447    where
448        I: IntoIterator<Item = F>,
449        F: Into<TellStatusField>,
450    {
451        Self::new(offset, num).fields(Some(fields))
452    }
453}
454
455tell_star!(TellWaiting);
456
457
458impl Call for TellWaiting {
459    type Response = Vec<TellStatusReply>;
460
461    fn method(&self) -> &'static str {
462        "aria2.tellWaiting"
463    }
464
465    fn serialize_params<S: SerializeSeq>(&self, serializer: &mut S) -> Result<(), S::Error> {
466        serializer.serialize_element(&self.offset)?;
467        serializer.serialize_element(&self.num)?;
468        option_element!(self.keys, serializer);
469        Ok(())
470    }
471}
472
473#[derive(Debug)]
474pub struct TellStopped {
475    pub offset: i32,
476    pub num: i32,
477    keys: Option<std::collections::HashSet<TellStatusField>>,
478}
479
480impl TellStopped {
481    pub fn new(offset: i32, num: i32) -> Self {
482        Self {
483            offset,
484            num,
485            keys: None,
486        }
487    }
488
489    pub fn new_with_fields<I, F>(offset: i32, num: i32, fields: I) -> Self
490    where
491        I: IntoIterator<Item = F>,
492        F: Into<TellStatusField>,
493    {
494        Self::new(offset, num).fields(Some(fields))
495    }
496}
497tell_star!(TellStopped);
498
499
500impl Call for TellStopped {
501    type Response = Vec<TellStatusReply>;
502
503    fn method(&self) -> &'static str {
504        "aria2.tellStopped"
505    }
506
507    fn serialize_params<S: SerializeSeq>(&self, serializer: &mut S) -> Result<(), S::Error> {
508        serializer.serialize_element(&self.offset)?;
509        serializer.serialize_element(&self.num)?;
510        option_element!(self.keys, serializer);
511        Ok(())
512    }
513}
514
515#[derive(Debug)]
516pub struct GetUris {
517    pub gid: String,
518}
519
520impl GetUris {
521    pub fn new<G: Into<String>>(gid: G) -> Self {
522        Self { gid: gid.into() }
523    }
524}
525impl Call for GetUris {
526    type Response = Vec<TellStatusReplyUri>;
527
528    fn method(&self) -> &'static str {
529        "aria2.getUris"
530    }
531
532    fn serialize_params<S: SerializeSeq>(&self, serializer: &mut S) -> Result<(), S::Error> {
533        serializer.serialize_element(&self.gid)?;
534        Ok(())
535    }
536}
537
538#[derive(Debug)]
539pub struct GetFiles {
540    pub gid: String,
541}
542impl GetFiles {
543    pub fn new<G: Into<String>>(gid: G) -> Self {
544        Self { gid: gid.into() }
545    }
546}
547impl Call for GetFiles {
548    type Response = Vec<TellStatusReplyFile>;
549
550    fn method(&self) -> &'static str {
551        "aria2.getFiles"
552    }
553
554    fn serialize_params<S: SerializeSeq>(&self, serializer: &mut S) -> Result<(), S::Error> {
555        serializer.serialize_element(&self.gid)?;
556        Ok(())
557    }
558}