pcloud/stream/
file.rs

1use std::borrow::Cow;
2
3use super::StreamingLinkList;
4use crate::file::FileIdentifier;
5
6/// Parameters for retrieving a file link, including options for controlling the download behavior and file metadata.
7#[derive(Debug, Default, serde::Serialize)]
8pub struct GetFileLinkParams<'a> {
9    /// Flag to force the file to be downloaded, rather than viewed in the browser.
10    #[serde(
11        rename = "forcedownload",
12        skip_serializing_if = "crate::request::is_false",
13        serialize_with = "crate::request::serialize_bool"
14    )]
15    force_download: bool,
16
17    /// The content type of the file (e.g., "application/pdf"). This is optional.
18    #[serde(rename = "contenttype", skip_serializing_if = "Option::is_none")]
19    content_type: Option<Cow<'a, str>>,
20
21    /// Maximum download speed (in bytes per second). This is optional.
22    #[serde(rename = "maxspeed", skip_serializing_if = "Option::is_none")]
23    max_speed: Option<u64>,
24
25    /// Flag to skip the filename in the file link. If true, the filename is not included in the response URL.
26    #[serde(
27        rename = "skip_filename",
28        skip_serializing_if = "crate::request::is_false",
29        serialize_with = "crate::request::serialize_bool"
30    )]
31    skip_filename: bool,
32}
33
34impl<'a> GetFileLinkParams<'a> {
35    /// Sets the `force_download` flag.
36    ///
37    /// # Arguments
38    ///
39    /// * `value` - Boolean indicating whether to force the download.
40    pub fn set_force_download(&mut self, value: bool) {
41        self.force_download = value;
42    }
43
44    /// Sets the `force_download` flag and returns the updated `GetFileLinkParams` object.
45    ///
46    /// # Arguments
47    ///
48    /// * `value` - Boolean indicating whether to force the download.
49    pub fn with_force_download(mut self, value: bool) -> Self {
50        self.set_force_download(value);
51        self
52    }
53
54    /// Sets the content type for the file link.
55    ///
56    /// # Arguments
57    ///
58    /// * `value` - Content type (e.g., "application/pdf").
59    pub fn set_content_type(&mut self, value: impl Into<Cow<'a, str>>) {
60        self.content_type = Some(value.into());
61    }
62
63    /// Sets the content type and returns the updated `GetFileLinkParams` object.
64    ///
65    /// # Arguments
66    ///
67    /// * `value` - Content type (e.g., "application/pdf").
68    pub fn with_content_type(mut self, value: impl Into<Cow<'a, str>>) -> Self {
69        self.set_content_type(value);
70        self
71    }
72
73    /// Sets the maximum download speed for the file.
74    ///
75    /// # Arguments
76    ///
77    /// * `value` - Maximum speed in bytes per second.
78    pub fn set_max_speed(&mut self, value: u64) {
79        self.max_speed = Some(value);
80    }
81
82    /// Sets the maximum download speed and returns the updated `GetFileLinkParams` object.
83    ///
84    /// # Arguments
85    ///
86    /// * `value` - Maximum speed in bytes per second.
87    pub fn with_max_speed(mut self, value: u64) -> Self {
88        self.set_max_speed(value);
89        self
90    }
91
92    /// Sets the `skip_filename` flag.
93    ///
94    /// # Arguments
95    ///
96    /// * `value` - Boolean indicating whether to skip the filename in the URL.
97    pub fn set_skip_filename(&mut self, value: bool) {
98        self.skip_filename = value;
99    }
100
101    /// Sets the `skip_filename` flag and returns the updated `GetFileLinkParams` object.
102    ///
103    /// # Arguments
104    ///
105    /// * `value` - Boolean indicating whether to skip the filename in the URL.
106    pub fn with_skip_filename(mut self, value: bool) -> Self {
107        self.set_skip_filename(value);
108        self
109    }
110}
111
112/// Struct representing the parameters used when making a request to get a file link.
113#[derive(serde::Serialize)]
114struct Params<'a> {
115    /// The identifier for the file being requested.
116    #[serde(flatten)]
117    identifier: FileIdentifier<'a>,
118
119    /// The parameters controlling how the file link should be generated.
120    #[serde(flatten)]
121    params: GetFileLinkParams<'a>,
122}
123
124impl crate::Client {
125    /// Gets a file link using only the file identifier, without additional parameters.
126    ///
127    /// # Arguments
128    ///
129    /// * `identifier` - The identifier of the file.
130    ///
131    /// # Returns
132    ///
133    /// A result containing the `StreamingLinkList` with the generated file links.
134    pub async fn get_file_link(
135        &self,
136        identifier: impl Into<FileIdentifier<'_>>,
137    ) -> crate::Result<StreamingLinkList> {
138        self.get_request::<StreamingLinkList, _>("getfilelink", identifier.into())
139            .await
140    }
141
142    /// Gets a file link using both the file identifier and additional parameters.
143    ///
144    /// # Arguments
145    ///
146    /// * `identifier` - The identifier of the file.
147    /// * `params` - The parameters to customize the file link (e.g., force download, content type, etc.).
148    ///
149    /// # Returns
150    ///
151    /// A result containing the `StreamingLinkList` with the generated file links.
152    pub async fn get_file_link_with_params(
153        &self,
154        identifier: impl Into<FileIdentifier<'_>>,
155        params: GetFileLinkParams<'_>,
156    ) -> crate::Result<StreamingLinkList> {
157        self.get_request::<StreamingLinkList, _>(
158            "getfilelink",
159            Params {
160                identifier: identifier.into(),
161                params,
162            },
163        )
164        .await
165    }
166}
167
168#[cfg(test)]
169mod tests {
170    use crate::{Client, Credentials};
171    use mockito::Matcher;
172
173    #[tokio::test]
174    async fn success() {
175        let mut server = mockito::Server::new_async().await;
176        let m = server.mock("GET", "/getfilelink")
177            .match_query(Matcher::AllOf(vec![
178                Matcher::UrlEncoded("access_token".into(), "access-token".into()),
179                Matcher::UrlEncoded("fileid".into(), "42".into()),
180            ]))
181            .with_status(200)
182            .with_body(r#"{
183        "result": 0,
184        "dwltag": "yvkNr0TqT6HFAWlVpdnHs5",
185        "hash": 17869736033964340520,
186        "size": 10485760,
187        "expires": "Sat, 24 Jul 2021 03:18:31 +0000",
188        "path": "\/DLZCAt2vXZejNfL5ZruLVZZTk2ev7Z2ZZNR5ZZdoz6ZXZQZZErw4bH0PfzBQt3LlgXMliXVtietX\/SAkdyBjkA7mQABbT.bin",
189        "hosts": [
190                "edef2.pcloud.com",
191                "eu3.pcloud.com"
192        ]
193}"#)
194.create();
195        let client = Client::new(server.url(), Credentials::access_token("access-token")).unwrap();
196        let result = client.get_file_link(42).await.unwrap();
197        let mut iter = result.links();
198        assert_eq!(iter.next().unwrap().to_string(), "https://edef2.pcloud.com/DLZCAt2vXZejNfL5ZruLVZZTk2ev7Z2ZZNR5ZZdoz6ZXZQZZErw4bH0PfzBQt3LlgXMliXVtietX/SAkdyBjkA7mQABbT.bin");
199        m.assert();
200    }
201}