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, UploadConfig, UploadOperator, Uploader}; 15 use crate::async_impl::MultiPart; 16 use crate::runtime::AsyncRead; 17 18 /// A builder that can create a `Uploader`. 19 /// 20 /// You can use this builder to build a `Uploader` step by step. 21 /// 22 /// # Examples 23 /// 24 /// ``` 25 /// # use ylong_http_client::async_impl::{UploaderBuilder, Uploader}; 26 /// 27 /// let uploader = UploaderBuilder::new() 28 /// .reader("HelloWorld".as_bytes()) 29 /// .console() 30 /// .build(); 31 /// ``` 32 pub struct UploaderBuilder<S> { 33 state: S, 34 } 35 36 /// A state indicates that `UploaderBuilder` wants a `Reader`. 37 pub struct WantsReader; 38 39 impl UploaderBuilder<WantsReader> { 40 /// Creates a `UploaderBuilder` in the `WantsReader` state. 41 /// 42 /// # Examples 43 /// 44 /// ``` 45 /// # use ylong_http_client::async_impl::UploaderBuilder; 46 /// 47 /// let builder = UploaderBuilder::new(); 48 /// ``` new() -> Self49 pub fn new() -> Self { 50 Self { state: WantsReader } 51 } 52 53 /// Sets a reader that needs to be read. 54 /// 55 /// # Examples 56 /// 57 /// ``` 58 /// # use ylong_http_client::async_impl::UploaderBuilder; 59 /// 60 /// let builder = UploaderBuilder::new().reader("HelloWorld".as_bytes()); 61 /// ``` reader<R: AsyncRead>(self, reader: R) -> UploaderBuilder<WantsOperator<R>>62 pub fn reader<R: AsyncRead>(self, reader: R) -> UploaderBuilder<WantsOperator<R>> { 63 UploaderBuilder { 64 state: WantsOperator { 65 reader, 66 config: UploadConfig::default(), 67 }, 68 } 69 } 70 71 /// Sets a `multipart` that needs to be read. The size of the multipart will 72 /// be set automatically if it contains. 73 /// 74 /// # Examples 75 /// 76 /// ``` 77 /// # use ylong_http_client::async_impl::UploaderBuilder; 78 /// 79 /// let builder = UploaderBuilder::new().reader("HelloWorld".as_bytes()); 80 /// ``` multipart(self, reader: MultiPart) -> UploaderBuilder<WantsOperator<MultiPart>>81 pub fn multipart(self, reader: MultiPart) -> UploaderBuilder<WantsOperator<MultiPart>> { 82 let total_bytes = reader.total_bytes(); 83 UploaderBuilder { 84 state: WantsOperator { 85 reader, 86 config: UploadConfig { total_bytes }, 87 }, 88 } 89 } 90 } 91 92 impl Default for UploaderBuilder<WantsReader> { default() -> Self93 fn default() -> Self { 94 Self::new() 95 } 96 } 97 98 /// A state indicates that `UploaderBuilder` wants an `UploadOperator`. 99 pub struct WantsOperator<R> { 100 reader: R, 101 config: UploadConfig, 102 } 103 104 impl<R: AsyncRead> UploaderBuilder<WantsOperator<R>> { 105 /// Sets a customized `UploaderOperator`. 106 /// 107 /// Then the `UploaderBuilder` will switch to `WantsConfig` state. 108 /// 109 /// # Examples 110 /// 111 /// ``` 112 /// # use std::pin::Pin; 113 /// # use std::task::{Context, Poll}; 114 /// # use ylong_http_client::async_impl::{UploaderBuilder, Uploader, UploadOperator, Response}; 115 /// # use ylong_http_client::HttpClientError; 116 /// 117 /// struct MyOperator; 118 /// 119 /// impl UploadOperator for MyOperator { 120 /// fn poll_progress( 121 /// self: Pin<&mut Self>, 122 /// cx: &mut Context<'_>, 123 /// uploaded: u64, 124 /// total: Option<u64>, 125 /// ) -> Poll<Result<(), HttpClientError>> { 126 /// todo!() 127 /// } 128 /// } 129 /// 130 /// let builder = UploaderBuilder::new() 131 /// .reader("HelloWorld".as_bytes()) 132 /// .operator(MyOperator); 133 /// ``` operator<T: UploadOperator>(self, operator: T) -> UploaderBuilder<WantsConfig<R, T>>134 pub fn operator<T: UploadOperator>(self, operator: T) -> UploaderBuilder<WantsConfig<R, T>> { 135 UploaderBuilder { 136 state: WantsConfig { 137 reader: self.state.reader, 138 operator, 139 config: self.state.config, 140 }, 141 } 142 } 143 144 /// Sets a `Console` to this `Uploader`. The download result and progress 145 /// will be displayed on the console. 146 /// 147 /// The `Console` needs a `Reader` to display. 148 /// 149 /// # Examples 150 /// 151 /// ``` 152 /// # use ylong_http_client::async_impl::{UploaderBuilder, Uploader, Response}; 153 /// 154 /// let builder = UploaderBuilder::new() 155 /// .reader("HelloWorld".as_bytes()) 156 /// .console(); 157 /// ``` console(self) -> UploaderBuilder<WantsConfig<R, Console>>158 pub fn console(self) -> UploaderBuilder<WantsConfig<R, Console>> { 159 UploaderBuilder { 160 state: WantsConfig { 161 reader: self.state.reader, 162 operator: Console, 163 config: self.state.config, 164 }, 165 } 166 } 167 } 168 169 /// A state indicates that `UploaderBuilder` wants some configurations. 170 pub struct WantsConfig<R, T> { 171 reader: R, 172 operator: T, 173 config: UploadConfig, 174 } 175 176 impl<R, T> UploaderBuilder<WantsConfig<R, T>> { 177 /// Sets the total bytes of the uploaded content. 178 /// 179 /// Default is `None` which means that you don't know the size of the 180 /// content. 181 /// 182 /// # Examples 183 /// 184 /// ``` 185 /// # use ylong_http_client::async_impl::{UploaderBuilder, Uploader}; 186 /// 187 /// let builder = UploaderBuilder::new() 188 /// .reader("HelloWorld".as_bytes()) 189 /// .console() 190 /// .total_bytes(Some(10)); 191 /// ``` total_bytes(mut self, total_bytes: Option<u64>) -> Self192 pub fn total_bytes(mut self, total_bytes: Option<u64>) -> Self { 193 self.state.config.total_bytes = total_bytes; 194 self 195 } 196 197 /// Returns a `Uploader` that uses this `UploaderBuilder` configuration. 198 /// 199 /// # Examples 200 /// 201 /// ``` 202 /// # use ylong_http_client::async_impl::{UploaderBuilder, Uploader, Response}; 203 /// 204 /// let uploader = UploaderBuilder::new() 205 /// .reader("HelloWorld".as_bytes()) 206 /// .console() 207 /// .build(); 208 /// ``` build(self) -> Uploader<R, T>209 pub fn build(self) -> Uploader<R, T> { 210 Uploader { 211 reader: self.state.reader, 212 operator: self.state.operator, 213 config: self.state.config, 214 info: None, 215 } 216 } 217 } 218