1 // Copyright (c) 2023 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 use super::{Console, DownloadConfig, DownloadOperator, Downloader};
15 use crate::async_impl::Response;
16 use crate::util::{SpeedLimit, Timeout};
17 
18 /// A builder that can create a `Downloader`.
19 ///
20 /// You can use this builder to build a `Downloader` step by step.
21 ///
22 /// # Examples
23 ///
24 /// ```
25 /// # use ylong_http_client::async_impl::{DownloaderBuilder, Downloader, HttpBody, Response};
26 ///
27 /// # async fn create_a_downloader(body: Response) {
28 /// let downloader = DownloaderBuilder::new().body(body).console().build();
29 /// # }
30 /// ```
31 pub struct DownloaderBuilder<S> {
32     state: S,
33 }
34 
35 /// A state indicates that `DownloaderBuilder` wants a body that needs to be
36 /// downloaded.
37 pub struct WantsBody;
38 
39 impl DownloaderBuilder<WantsBody> {
40     /// Creates a `DownloaderBuilder` in the `WantsBody` state.
41     ///
42     /// # Examples
43     ///
44     /// ```
45     /// # use ylong_http_client::async_impl::DownloaderBuilder;
46     ///
47     /// let builder = DownloaderBuilder::new();
48     /// ```
new() -> Self49     pub fn new() -> Self {
50         Self { state: WantsBody }
51     }
52 
53     /// Sets a body part that needs to be downloaded by the downloader.
54     ///
55     /// Then the `DownloaderBuilder` will switch to `WantsOperator` state.
56     ///
57     /// # Examples
58     ///
59     /// ```
60     /// # use ylong_http_client::async_impl::{DownloaderBuilder, Downloader, HttpBody, Response};
61     ///
62     /// # async fn set_body(body: Response) {
63     /// let builder = DownloaderBuilder::new().body(body);
64     /// # }
65     /// ```
body(self, body: Response) -> DownloaderBuilder<WantsOperator>66     pub fn body(self, body: Response) -> DownloaderBuilder<WantsOperator> {
67         DownloaderBuilder {
68             state: WantsOperator { body },
69         }
70     }
71 }
72 
73 impl Default for DownloaderBuilder<WantsBody> {
default() -> Self74     fn default() -> Self {
75         Self::new()
76     }
77 }
78 
79 /// A state indicates that `DownloaderBuilder` wants an `DownloadOperator`.
80 pub struct WantsOperator {
81     body: Response,
82 }
83 
84 impl DownloaderBuilder<WantsOperator> {
85     /// Sets a customized `DownloaderBuilder`.
86     ///
87     /// Then the `DownloaderBuilder` will switch to `WantsConfig` state.
88     ///
89     /// # Examples
90     ///
91     /// ```
92     /// # use std::pin::Pin;
93     /// # use std::task::{Context, Poll};
94     /// # use ylong_http_client::async_impl::{DownloaderBuilder, Downloader, DownloadOperator, HttpBody, Response};
95     /// # use ylong_http_client::HttpClientError;
96     ///
97     /// # async fn set_downloader_operator(body: Response) {
98     /// struct MyOperator;
99     ///
100     /// impl DownloadOperator for MyOperator {
101     ///     fn poll_download(
102     ///         self: Pin<&mut Self>,
103     ///         cx: &mut Context<'_>,
104     ///         data: &[u8]
105     ///     ) -> Poll<Result<usize, HttpClientError>> {
106     ///         todo!()
107     ///     }
108     ///
109     ///     fn poll_progress(
110     ///         self: Pin<&mut Self>,
111     ///         cx: &mut Context<'_>,
112     ///         downloaded: u64,
113     ///         total: Option<u64>
114     ///     ) -> Poll<Result<(), HttpClientError>> {
115     ///         todo!()
116     ///     }
117     /// }
118     ///
119     /// let builder = DownloaderBuilder::new().body(body).operator(MyOperator);
120     /// # }
121     /// ```
operator<T: DownloadOperator>(self, operator: T) -> DownloaderBuilder<WantsConfig<T>>122     pub fn operator<T: DownloadOperator>(self, operator: T) -> DownloaderBuilder<WantsConfig<T>> {
123         DownloaderBuilder {
124             state: WantsConfig {
125                 body: self.state.body,
126                 operator,
127                 config: DownloadConfig::default(),
128             },
129         }
130     }
131 
132     /// Sets a `Console` to this `Downloader`. The download result and progress
133     /// will be displayed on the console.
134     ///
135     /// # Examples
136     ///
137     /// ```
138     /// # use ylong_http_client::async_impl::{DownloaderBuilder, Downloader, HttpBody, Response};
139     ///
140     /// # async fn set_console(body: Response) {
141     /// let builder = DownloaderBuilder::new().body(body).console();
142     /// # }
143     /// ```
console(self) -> DownloaderBuilder<WantsConfig<Console>>144     pub fn console(self) -> DownloaderBuilder<WantsConfig<Console>> {
145         DownloaderBuilder {
146             state: WantsConfig {
147                 body: self.state.body,
148                 operator: Console,
149                 config: DownloadConfig::default(),
150             },
151         }
152     }
153 }
154 
155 /// A state indicates that `DownloaderBuilder` wants some configurations.
156 pub struct WantsConfig<T: DownloadOperator> {
157     body: Response,
158     operator: T,
159     config: DownloadConfig,
160 }
161 
162 impl<T: DownloadOperator> DownloaderBuilder<WantsConfig<T>> {
163     /// Sets the timeout for downloading body.
164     ///
165     /// Default is `Timeout::none()`.
166     ///
167     /// # Examples
168     ///
169     /// ```
170     /// # use ylong_http_client::async_impl::{DownloaderBuilder, Downloader, HttpBody, Response};
171     /// # use ylong_http_client::Timeout;
172     ///
173     /// # async fn set_timeout(body: Response) {
174     /// let builder = DownloaderBuilder::new()
175     ///     .body(body)
176     ///     .console()
177     ///     .timeout(Timeout::none());
178     /// # }
179     /// ```
timeout(mut self, timeout: Timeout) -> Self180     pub fn timeout(mut self, timeout: Timeout) -> Self {
181         self.state.config.timeout = timeout;
182         self
183     }
184 
185     /// Sets the speed limit for downloading body.
186     ///
187     /// Default is `SpeedLimit::none()`.
188     ///
189     /// # Examples
190     ///
191     /// ```
192     /// # use ylong_http_client::async_impl::{DownloaderBuilder, Downloader, HttpBody, Response};
193     /// # use ylong_http_client::SpeedLimit;
194     ///
195     /// # async fn set_timeout(body: Response) {
196     /// let builder = DownloaderBuilder::new()
197     ///     .body(body)
198     ///     .console()
199     ///     .speed_limit(SpeedLimit::none());
200     /// # }
201     /// ```
speed_limit(mut self, speed_limit: SpeedLimit) -> Self202     pub fn speed_limit(mut self, speed_limit: SpeedLimit) -> Self {
203         self.state.config.speed_limit = speed_limit;
204         self
205     }
206 
207     /// Returns a `Downloader` that uses this `DownloaderBuilder` configuration.
208     ///
209     /// # Examples
210     ///
211     /// ```
212     /// # use ylong_http_client::async_impl::{DownloaderBuilder, Downloader, HttpBody, Response};
213     ///
214     /// # async fn build_downloader(body: Response) {
215     /// let downloader = DownloaderBuilder::new().body(body).console().build();
216     /// # }
217     /// ```
build(self) -> Downloader<T>218     pub fn build(self) -> Downloader<T> {
219         Downloader {
220             body: self.state.body,
221             operator: self.state.operator,
222             config: self.state.config,
223             info: None,
224         }
225     }
226 }
227