aria2_rs/
call.rs

1use std::borrow::Cow;
2
3use serde::{de::DeserializeOwned, ser::SerializeSeq as _, Deserialize, Serializer};
4use serde_json::Value;
5
6use crate::{options::TaskOptions, SmallString, SmallVec};
7
8type SerializeSeq = <serde_json::value::Serializer as serde::ser::Serializer>::SerializeSeq;
9type JsonError = serde_json::Error;
10
11macro_rules! option {
12    ($opt: expr, $serializer: expr) => {
13        if let Some(value) = $opt {
14            $serializer.serialize_element(value)?;
15        }
16    };
17}
18macro_rules! empty {
19    ($map: expr, $serializer: expr) => {
20        if !$map.is_empty() {
21            $serializer.serialize_element($map)?;
22        }
23    };
24}
25
26pub trait Reply {
27    type Reply: DeserializeOwned;
28    #[inline]
29    #[allow(clippy::result_large_err)]
30    fn to_reply(value: Value) -> crate::Result<Self::Reply> {
31        serde_json::from_value::<Self::Reply>(value).map_err(crate::Error::Decode)
32    }
33}
34
35pub trait Call {
36    // Why not define as a const: to make it object safe.
37    fn method(&self) -> &'static str;
38    fn serialize_params(
39        &self,
40        serializer: &mut SerializeSeq,
41        token: Option<&str>,
42    ) -> Result<(), JsonError>;
43
44    fn to_param(&self, token: Option<&str>) -> std::result::Result<Value, serde_json::Error> {
45        let mut serializer = serde_json::value::Serializer.serialize_seq(None)?;
46        self.serialize_params(&mut serializer, token)?;
47        serializer.end()
48    }
49}
50
51pub struct AddUriCall {
52    pub uris: SmallVec<String>,
53    pub options: Option<TaskOptions>,
54}
55
56impl Reply for AddUriCall {
57    type Reply = GidReply;
58}
59
60#[derive(Deserialize, Debug, Clone)]
61#[serde(transparent)]
62pub struct GidReply(pub SmallString);
63
64impl Call for AddUriCall {
65    fn method(&self) -> &'static str {
66        "aria2.addUri"
67    }
68    fn serialize_params(
69        &self,
70        serializer: &mut SerializeSeq,
71        token: Option<&str>,
72    ) -> Result<(), JsonError> {
73        option!(token, serializer);
74        serializer.serialize_element(&self.uris)?;
75        option!(&self.options, serializer);
76        Ok(())
77    }
78}
79
80pub struct AddTorrentCall<'a> {
81    pub torrent: Cow<'a, [u8]>,
82    pub uris: SmallVec<Cow<'a, str>>,
83    pub options: Option<TaskOptions>,
84}
85
86impl Reply for AddTorrentCall<'_> {
87    type Reply = GidReply;
88}
89
90impl Call for AddTorrentCall<'_> {
91    fn method(&self) -> &'static str {
92        "aria2.addTorrent"
93    }
94    fn serialize_params(
95        &self,
96        serializer: &mut SerializeSeq,
97        token: Option<&str>,
98    ) -> Result<(), JsonError> {
99        use base64::{engine::general_purpose, Engine as _};
100        let encoded: String = general_purpose::STANDARD.encode(&self.torrent);
101
102        option!(token, serializer);
103        serializer.serialize_element(&encoded)?;
104        serializer.serialize_element(&self.uris)?;
105        option!(&self.options, serializer);
106        Ok(())
107    }
108}
109
110pub struct AddMetalinkCall<'a> {
111    pub metalink: Cow<'a, str>,
112    pub options: Option<TaskOptions>,
113}
114
115impl Reply for AddMetalinkCall<'_> {
116    type Reply = Vec<GidReply>;
117}
118
119impl Call for AddMetalinkCall<'_> {
120    fn method(&self) -> &'static str {
121        "aria2.addMetalink"
122    }
123    fn serialize_params(
124        &self,
125        serializer: &mut SerializeSeq,
126        token: Option<&str>,
127    ) -> Result<(), JsonError> {
128        option!(token, serializer);
129        serializer.serialize_element(&self.metalink)?;
130        option!(&self.options, serializer);
131        Ok(())
132    }
133}
134
135pub struct RemoveCall<'a> {
136    pub gid: Cow<'a, str>,
137}
138
139impl Reply for RemoveCall<'_> {
140    type Reply = GidReply;
141}
142
143impl Call for RemoveCall<'_> {
144    fn method(&self) -> &'static str {
145        "aria2.remove"
146    }
147    fn serialize_params(
148        &self,
149        serializer: &mut SerializeSeq,
150        token: Option<&str>,
151    ) -> Result<(), JsonError> {
152        option!(token, serializer);
153        serializer.serialize_element(&self.gid)?;
154        Ok(())
155    }
156}
157
158pub struct ForceRemoveCall<'a> {
159    pub gid: Cow<'a, str>,
160}
161
162impl Reply for ForceRemoveCall<'_> {
163    type Reply = GidReply;
164}
165
166impl Call for ForceRemoveCall<'_> {
167    fn method(&self) -> &'static str {
168        "aria2.forceRemove"
169    }
170    fn serialize_params(
171        &self,
172        serializer: &mut SerializeSeq,
173        token: Option<&str>,
174    ) -> Result<(), JsonError> {
175        option!(token, serializer);
176        serializer.serialize_element(&self.gid)?;
177        Ok(())
178    }
179}
180
181pub struct PauseCall<'a> {
182    pub gid: Cow<'a, str>,
183}
184
185impl Reply for PauseCall<'_> {
186    type Reply = GidReply;
187}
188
189impl Call for PauseCall<'_> {
190    fn method(&self) -> &'static str {
191        "aria2.pause"
192    }
193    fn serialize_params(
194        &self,
195        serializer: &mut SerializeSeq,
196        token: Option<&str>,
197    ) -> Result<(), JsonError> {
198        option!(token, serializer);
199        serializer.serialize_element(&self.gid)?;
200        Ok(())
201    }
202}
203
204pub struct ForcePauseCall<'a> {
205    pub gid: Cow<'a, str>,
206}
207
208impl Reply for ForcePauseCall<'_> {
209    type Reply = GidReply;
210}
211
212impl Call for ForcePauseCall<'_> {
213    fn method(&self) -> &'static str {
214        "aria2.forcePause"
215    }
216    fn serialize_params(
217        &self,
218        serializer: &mut SerializeSeq,
219        token: Option<&str>,
220    ) -> Result<(), JsonError> {
221        option!(token, serializer);
222        serializer.serialize_element(&self.gid)?;
223        Ok(())
224    }
225}
226
227pub struct UnpauseCall<'a> {
228    pub gid: Cow<'a, str>,
229}
230
231impl Reply for UnpauseCall<'_> {
232    type Reply = GidReply;
233}
234
235impl Call for UnpauseCall<'_> {
236    fn method(&self) -> &'static str {
237        "aria2.unpause"
238    }
239    fn serialize_params(
240        &self,
241        serializer: &mut SerializeSeq,
242        token: Option<&str>,
243    ) -> Result<(), JsonError> {
244        option!(token, serializer);
245        serializer.serialize_element(&self.gid)?;
246        Ok(())
247    }
248}
249
250pub struct TellStatusCall<'a> {
251    pub gid: Cow<'a, str>,
252    pub keys: SmallVec<crate::status::StatusKey>,
253}
254
255impl Reply for TellStatusCall<'_> {
256    type Reply = crate::status::Status;
257}
258
259impl Call for TellStatusCall<'_> {
260    fn method(&self) -> &'static str {
261        "aria2.tellStatus"
262    }
263    fn serialize_params(
264        &self,
265        serializer: &mut SerializeSeq,
266        token: Option<&str>,
267    ) -> Result<(), JsonError> {
268        option!(token, serializer);
269        serializer.serialize_element(&self.gid)?;
270        empty!(&self.keys, serializer);
271        Ok(())
272    }
273}
274
275#[derive(Debug, Default, Clone)]
276pub struct TellActiveCall {
277    pub keys: SmallVec<crate::status::StatusKey>,
278}
279
280impl Reply for TellActiveCall {
281    type Reply = Vec<crate::status::Status>;
282}
283
284impl Call for TellActiveCall {
285    fn method(&self) -> &'static str {
286        "aria2.tellActive"
287    }
288    fn serialize_params(
289        &self,
290        serializer: &mut SerializeSeq,
291        token: Option<&str>,
292    ) -> Result<(), JsonError> {
293        option!(token, serializer);
294        empty!(&self.keys, serializer);
295        Ok(())
296    }
297}
298
299#[derive(Debug, Default, Clone)]
300pub struct TellWaitingCall {
301    pub offset: i32,
302    pub num: i32,
303    pub keys: SmallVec<crate::status::StatusKey>,
304}
305
306impl Reply for TellWaitingCall {
307    type Reply = Vec<crate::status::Status>;
308}
309
310impl Call for TellWaitingCall {
311    fn method(&self) -> &'static str {
312        "aria2.tellWaiting"
313    }
314    fn serialize_params(
315        &self,
316        serializer: &mut SerializeSeq,
317        token: Option<&str>,
318    ) -> Result<(), JsonError> {
319        option!(token, serializer);
320        serializer.serialize_element(&self.offset)?;
321        serializer.serialize_element(&self.num)?;
322        empty!(&self.keys, serializer);
323        Ok(())
324    }
325}
326
327#[derive(Debug, Default, Clone)]
328pub struct TellStoppedCall {
329    pub offset: i32,
330    pub num: i32,
331    pub keys: SmallVec<crate::status::StatusKey>,
332}
333
334impl Reply for TellStoppedCall {
335    type Reply = Vec<crate::status::Status>;
336}
337
338impl Call for TellStoppedCall {
339    fn method(&self) -> &'static str {
340        "aria2.tellStopped"
341    }
342    fn serialize_params(
343        &self,
344        serializer: &mut SerializeSeq,
345        token: Option<&str>,
346    ) -> Result<(), JsonError> {
347        option!(token, serializer);
348        serializer.serialize_element(&self.offset)?;
349        serializer.serialize_element(&self.num)?;
350        empty!(&self.keys, serializer);
351        Ok(())
352    }
353}
354
355#[derive(Debug, Default, Clone)]
356pub struct GetGlobalStatCall {
357    pub keys: SmallVec<crate::status::StatKey>,
358}
359
360impl Reply for GetGlobalStatCall {
361    type Reply = crate::status::Stat;
362}
363
364impl Call for GetGlobalStatCall {
365    fn method(&self) -> &'static str {
366        "aria2.getGlobalStat"
367    }
368    fn serialize_params(
369        &self,
370        serializer: &mut SerializeSeq,
371        token: Option<&str>,
372    ) -> Result<(), JsonError> {
373        option!(token, serializer);
374        empty!(&self.keys, serializer);
375        Ok(())
376    }
377}
378
379#[derive(Debug, Default, Clone, Copy)]
380pub struct PurgeDownloadResultCall;
381
382#[derive(Debug, Clone)]
383pub enum OK {
384    Ok,
385    Err(String),
386}
387
388impl<'de> serde::de::Deserialize<'de> for OK {
389    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
390    where
391        D: serde::Deserializer<'de>,
392    {
393        String::deserialize(deserializer).map(|s| if s == "OK" { OK::Ok } else { OK::Err(s) })
394    }
395}
396
397impl Reply for PurgeDownloadResultCall {
398    type Reply = OK;
399}
400
401impl Call for PurgeDownloadResultCall {
402    fn method(&self) -> &'static str {
403        "aria2.purgeDownloadResult"
404    }
405    fn serialize_params(
406        &self,
407        serializer: &mut SerializeSeq,
408        token: Option<&str>,
409    ) -> Result<(), JsonError> {
410        option!(token, serializer);
411        Ok(())
412    }
413}
414
415#[derive(Default)]
416pub struct MultiCall<'a> {
417    pub calls: Vec<Box<dyn Call + Send + Sync + 'a>>,
418}
419
420#[derive(Debug, Clone)]
421pub struct MultiResponse(pub SmallVec<Value>);
422
423impl<'de> Deserialize<'de> for MultiResponse {
424    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
425    where
426        D: serde::Deserializer<'de>,
427    {
428        let inner = SmallVec::<SmallVec<Value>>::deserialize(deserializer)?;
429        Ok(MultiResponse(inner.into_iter().flatten().collect()))
430    }
431}
432
433impl Reply for MultiCall<'_> {
434    type Reply = MultiResponse;
435}
436
437impl<'a> MultiCall<'a> {
438    pub const fn new() -> Self {
439        Self { calls: Vec::new() }
440    }
441    pub fn push<T: Call + Send + Sync + 'a>(&mut self, call: T) {
442        self.calls.push(Box::new(call));
443    }
444}
445
446impl Call for MultiCall<'_> {
447    fn method(&self) -> &'static str {
448        "system.multicall"
449    }
450    fn serialize_params(
451        &self,
452        serializer: &mut SerializeSeq,
453        token: Option<&str>,
454    ) -> Result<(), JsonError> {
455        #[derive(serde::Serialize)]
456        struct MultiCallParam {
457            #[serde(rename = "methodName")]
458            method_name: &'static str,
459            params: Value,
460        }
461
462        let mut values = SmallVec::with_capacity(self.calls.len());
463        for call in &self.calls {
464            let param = MultiCallParam {
465                method_name: call.method(),
466                params: call.to_param(token)?,
467            };
468            values.push(param);
469        }
470        serializer.serialize_element(&values)?;
471        Ok(())
472    }
473}