• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // TODO: Adapter, use Response<HttpBody> later.
16 use crate::async_impl::Response;
17 use crate::{SpeedLimit, Timeout};
18 
19 /// A builder that can create a `Downloader`.
20 ///
21 /// You can use this builder to build a `Downloader` step by step.
22 ///
23 /// # Examples
24 ///
25 /// ```
26 /// # use ylong_http_client::async_impl::{DownloaderBuilder, Downloader, HttpBody, Response};
27 ///
28 /// # async fn create_a_downloader(body: Response) {
29 /// let downloader = DownloaderBuilder::new().body(body).console().build();
30 /// # }
31 /// ```
32 pub struct DownloaderBuilder<S> {
33     state: S,
34 }
35 
36 /// A state indicates that `DownloaderBuilder` wants a body that needs to be
37 /// downloaded.
38 pub struct WantsBody;
39 
40 impl DownloaderBuilder<WantsBody> {
41     /// Creates a `DownloaderBuilder` in the `WantsBody` state.
42     ///
43     /// # Examples
44     ///
45     /// ```
46     /// # use ylong_http_client::async_impl::DownloaderBuilder;
47     ///
48     /// let builder = DownloaderBuilder::new();
49     /// ```
new() -> Self50     pub fn new() -> Self {
51         Self { state: WantsBody }
52     }
53 
54     /// Sets a body part that needs to be downloaded by the downloader.
55     ///
56     /// Then the `DownloaderBuilder` will switch to `WantsOperator` state.
57     ///
58     /// # Examples
59     ///
60     /// ```
61     /// # use ylong_http_client::async_impl::{DownloaderBuilder, Downloader, HttpBody, Response};
62     ///
63     /// # async fn set_body(body: Response) {
64     /// let builder = DownloaderBuilder::new().body(body);
65     /// # }
66     /// ```
body(self, body: Response) -> DownloaderBuilder<WantsOperator>67     pub fn body(self, body: Response) -> DownloaderBuilder<WantsOperator> {
68         DownloaderBuilder {
69             state: WantsOperator { body },
70         }
71     }
72 }
73 
74 impl Default for DownloaderBuilder<WantsBody> {
default() -> Self75     fn default() -> Self {
76         Self::new()
77     }
78 }
79 
80 /// A state indicates that `DownloaderBuilder` wants an `DownloadOperator`.
81 pub struct WantsOperator {
82     body: Response,
83 }
84 
85 impl DownloaderBuilder<WantsOperator> {
86     /// Sets a customized `DownloaderBuilder`.
87     ///
88     /// Then the `DownloaderBuilder` will switch to `WantsConfig` state.
89     ///
90     /// # Examples
91     ///
92     /// ```
93     /// # use std::pin::Pin;
94     /// # use std::task::{Context, Poll};
95     /// # use ylong_http_client::async_impl::{DownloaderBuilder, Downloader, DownloadOperator, HttpBody, Response};
96     /// # use ylong_http_client::HttpClientError;
97     ///
98     /// # async fn set_downloader_operator(body: Response) {
99     /// struct MyOperator;
100     ///
101     /// impl DownloadOperator for MyOperator {
102     ///     fn poll_download(
103     ///         self: Pin<&mut Self>,
104     ///         cx: &mut Context<'_>,
105     ///         data: &[u8]
106     ///     ) -> Poll<Result<usize, HttpClientError>> {
107     ///         todo!()
108     ///     }
109     ///
110     ///     fn poll_progress(
111     ///         self: Pin<&mut Self>,
112     ///         cx: &mut Context<'_>,
113     ///         downloaded: u64,
114     ///         total: Option<u64>
115     ///     ) -> Poll<Result<(), HttpClientError>> {
116     ///         todo!()
117     ///     }
118     /// }
119     ///
120     /// let builder = DownloaderBuilder::new().body(body).operator(MyOperator);
121     /// # }
122     /// ```
operator<T: DownloadOperator>(self, operator: T) -> DownloaderBuilder<WantsConfig<T>>123     pub fn operator<T: DownloadOperator>(self, operator: T) -> DownloaderBuilder<WantsConfig<T>> {
124         DownloaderBuilder {
125             state: WantsConfig {
126                 body: self.state.body,
127                 operator,
128                 config: DownloadConfig::default(),
129             },
130         }
131     }
132 
133     /// Sets a `Console` to this `Downloader`. The download result and progress
134     /// will be displayed on the console.
135     ///
136     /// # Examples
137     ///
138     /// ```
139     /// # use ylong_http_client::async_impl::{DownloaderBuilder, Downloader, HttpBody, Response};
140     ///
141     /// # async fn set_console(body: Response) {
142     /// let builder = DownloaderBuilder::new().body(body).console();
143     /// # }
144     /// ```
console(self) -> DownloaderBuilder<WantsConfig<Console>>145     pub fn console(self) -> DownloaderBuilder<WantsConfig<Console>> {
146         DownloaderBuilder {
147             state: WantsConfig {
148                 body: self.state.body,
149                 operator: Console,
150                 config: DownloadConfig::default(),
151             },
152         }
153     }
154 }
155 
156 /// A state indicates that `DownloaderBuilder` wants some configurations.
157 pub struct WantsConfig<T: DownloadOperator> {
158     body: Response,
159     operator: T,
160     config: DownloadConfig,
161 }
162 
163 impl<T: DownloadOperator> DownloaderBuilder<WantsConfig<T>> {
164     /// Sets the timeout for downloading body.
165     ///
166     /// Default is `Timeout::none()`.
167     ///
168     /// # Examples
169     ///
170     /// ```
171     /// # use ylong_http_client::async_impl::{DownloaderBuilder, Downloader, HttpBody, Response};
172     /// # use ylong_http_client::Timeout;
173     ///
174     /// # async fn set_timeout(body: Response) {
175     /// let builder = DownloaderBuilder::new()
176     ///     .body(body)
177     ///     .console()
178     ///     .timeout(Timeout::none());
179     /// # }
180     /// ```
timeout(mut self, timeout: Timeout) -> Self181     pub fn timeout(mut self, timeout: Timeout) -> Self {
182         self.state.config.timeout = timeout;
183         self
184     }
185 
186     /// Sets the speed limit for downloading body.
187     ///
188     /// Default is `SpeedLimit::none()`.
189     ///
190     /// # Examples
191     ///
192     /// ```
193     /// # use ylong_http_client::async_impl::{DownloaderBuilder, Downloader, HttpBody, Response};
194     /// # use ylong_http_client::SpeedLimit;
195     ///
196     /// # async fn set_timeout(body: Response) {
197     /// let builder = DownloaderBuilder::new()
198     ///     .body(body)
199     ///     .console()
200     ///     .speed_limit(SpeedLimit::none());
201     /// # }
202     /// ```
speed_limit(mut self, speed_limit: SpeedLimit) -> Self203     pub fn speed_limit(mut self, speed_limit: SpeedLimit) -> Self {
204         self.state.config.speed_limit = speed_limit;
205         self
206     }
207 
208     /// Returns a `Downloader` that uses this `DownloaderBuilder` configuration.
209     ///
210     /// # Examples
211     ///
212     /// ```
213     /// # use ylong_http_client::async_impl::{DownloaderBuilder, Downloader, HttpBody, Response};
214     ///
215     /// # async fn build_downloader(body: Response) {
216     /// let downloader = DownloaderBuilder::new().body(body).console().build();
217     /// # }
218     /// ```
build(self) -> Downloader<T>219     pub fn build(self) -> Downloader<T> {
220         Downloader {
221             body: self.state.body,
222             operator: self.state.operator,
223             config: self.state.config,
224             info: None,
225         }
226     }
227 }
228