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