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::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}; 115 /// # use ylong_http_client::{HttpClientError, Response}; 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}; 153 /// # use ylong_http_client::Response; 154 /// 155 /// let builder = UploaderBuilder::new() 156 /// .reader("HelloWorld".as_bytes()) 157 /// .console(); 158 /// ``` console(self) -> UploaderBuilder<WantsConfig<R, Console>>159 pub fn console(self) -> UploaderBuilder<WantsConfig<R, Console>> { 160 UploaderBuilder { 161 state: WantsConfig { 162 reader: self.state.reader, 163 operator: Console, 164 config: self.state.config, 165 }, 166 } 167 } 168 } 169 170 /// A state indicates that `UploaderBuilder` wants some configurations. 171 pub struct WantsConfig<R, T> { 172 reader: R, 173 operator: T, 174 config: UploadConfig, 175 } 176 177 impl<R, T> UploaderBuilder<WantsConfig<R, T>> { 178 /// Sets the total bytes of the uploaded content. 179 /// 180 /// Default is `None` which means that you don't know the size of the 181 /// content. 182 /// 183 /// # Examples 184 /// 185 /// ``` 186 /// # use ylong_http_client::async_impl::{UploaderBuilder, Uploader}; 187 /// 188 /// let builder = UploaderBuilder::new() 189 /// .reader("HelloWorld".as_bytes()) 190 /// .console() 191 /// .total_bytes(Some(10)); 192 /// ``` total_bytes(mut self, total_bytes: Option<u64>) -> Self193 pub fn total_bytes(mut self, total_bytes: Option<u64>) -> Self { 194 self.state.config.total_bytes = total_bytes; 195 self 196 } 197 198 /// Returns a `Uploader` that uses this `UploaderBuilder` configuration. 199 /// 200 /// # Examples 201 /// 202 /// ``` 203 /// # use ylong_http_client::async_impl::{UploaderBuilder, Uploader}; 204 /// # use ylong_http_client::Response; 205 /// 206 /// let uploader = UploaderBuilder::new() 207 /// .reader("HelloWorld".as_bytes()) 208 /// .console() 209 /// .build(); 210 /// ``` build(self) -> Uploader<R, T>211 pub fn build(self) -> Uploader<R, T> { 212 Uploader { 213 reader: self.state.reader, 214 operator: self.state.operator, 215 config: self.state.config, 216 info: None, 217 } 218 } 219 } 220