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