qiniu_upload_manager/
upload_token.rs

1use anyhow::Result as AnyResult;
2use assert_impl::assert_impl;
3use qiniu_apis::{
4    credential::{AccessKey, CredentialProvider},
5    http::ResponseErrorKind as HttpResponseErrorKind,
6    http_client::{ApiResult, ResponseError},
7};
8use qiniu_upload_token::{
9    BucketName, BucketUploadTokenProvider, ObjectName, ObjectUploadTokenProvider, UploadPolicyBuilder,
10    UploadTokenProvider, UploadTokenProviderExt,
11};
12use std::{
13    fmt::{self, Debug},
14    sync::Arc,
15    time::Duration,
16};
17
18/// 上传凭证签发器
19#[derive(Clone, Debug)]
20pub struct UploadTokenSigner(UploadTokenSignerInner);
21
22#[derive(Clone, Debug)]
23enum UploadTokenSignerInner {
24    UploadTokenProvider(Arc<dyn UploadTokenProvider>),
25    CredentialProvider(UploadTokenCredentialSigner),
26}
27
28type OnPolicyGeneratedCallback = Arc<dyn Fn(&mut UploadPolicyBuilder) -> AnyResult<()> + Sync + Send + 'static>;
29
30#[derive(Clone)]
31struct UploadTokenCredentialSigner {
32    credential: Arc<dyn CredentialProvider>,
33    bucket_name: BucketName,
34    lifetime: Duration,
35    on_policy_generated: Option<OnPolicyGeneratedCallback>,
36}
37
38impl Debug for UploadTokenCredentialSigner {
39    #[inline]
40    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41        f.debug_struct("UploadTokenCredentialSigner")
42            .field("credential", &self.credential)
43            .field("bucket_name", &self.bucket_name)
44            .field("lifetime", &self.lifetime)
45            .finish()
46    }
47}
48
49impl UploadTokenSigner {
50    /// 根据上传凭证提供者创建上传凭证签发器
51    #[inline]
52    pub fn new_upload_token_provider(upload_token_provider: impl UploadTokenProvider + 'static) -> Self {
53        Self(UploadTokenSignerInner::UploadTokenProvider(Arc::new(
54            upload_token_provider,
55        )))
56    }
57
58    /// 根据认证信息提供者和存储空间名称创建上传凭证签发器
59    #[inline]
60    pub fn new_credential_provider(
61        credential: impl CredentialProvider + 'static,
62        bucket_name: impl Into<BucketName>,
63        lifetime: Duration,
64    ) -> Self {
65        Self(UploadTokenSignerInner::CredentialProvider(
66            UploadTokenCredentialSigner {
67                credential: Arc::new(credential),
68                bucket_name: bucket_name.into(),
69                lifetime,
70                on_policy_generated: None,
71            },
72        ))
73    }
74
75    /// 根据认证信息提供者和存储空间名称创建上传凭证签发构建器
76    #[inline]
77    pub fn new_credential_provider_builder(
78        credential: impl CredentialProvider + 'static,
79        bucket_name: impl Into<BucketName>,
80        lifetime: Duration,
81    ) -> UploadTokenSignerBuilder {
82        UploadTokenSignerBuilder::new_credential_provider(credential, bucket_name, lifetime)
83    }
84
85    /// 获取上传凭证提供者
86    ///
87    /// 如果没有设置则返回 [`None`]
88    #[inline]
89    pub fn upload_token_provider(&self) -> Option<&dyn UploadTokenProvider> {
90        match &self.0 {
91            UploadTokenSignerInner::UploadTokenProvider(provider) => Some(provider.as_ref()),
92            UploadTokenSignerInner::CredentialProvider { .. } => None,
93        }
94    }
95
96    /// 获取认证信息提供者
97    ///
98    /// 如果没有设置则返回 [`None`]
99    #[inline]
100    pub fn credential_provider(&self) -> Option<&dyn CredentialProvider> {
101        match &self.0 {
102            UploadTokenSignerInner::UploadTokenProvider(_) => None,
103            UploadTokenSignerInner::CredentialProvider(UploadTokenCredentialSigner { credential, .. }) => {
104                Some(credential.as_ref())
105            }
106        }
107    }
108
109    pub(super) fn access_key(&self) -> ApiResult<AccessKey> {
110        match &self.0 {
111            UploadTokenSignerInner::UploadTokenProvider(provider) => provider
112                .access_key(Default::default())
113                .map(|ak| ak.into())
114                .map_err(|err| ResponseError::new(HttpResponseErrorKind::InvalidRequestResponse.into(), err)),
115            UploadTokenSignerInner::CredentialProvider(UploadTokenCredentialSigner { credential, .. }) => {
116                Ok(credential.get(Default::default())?.access_key().to_owned())
117            }
118        }
119    }
120
121    pub(super) fn bucket_name(&self) -> ApiResult<BucketName> {
122        match &self.0 {
123            UploadTokenSignerInner::UploadTokenProvider(provider) => provider
124                .bucket_name(Default::default())
125                .map_err(|err| ResponseError::new(HttpResponseErrorKind::InvalidRequestResponse.into(), err)),
126            UploadTokenSignerInner::CredentialProvider(UploadTokenCredentialSigner { bucket_name, .. }) => {
127                Ok(bucket_name.to_owned())
128            }
129        }
130    }
131
132    #[cfg(feature = "async")]
133    pub(super) async fn async_access_key(&self) -> ApiResult<AccessKey> {
134        match &self.0 {
135            UploadTokenSignerInner::UploadTokenProvider(provider) => provider
136                .async_access_key(Default::default())
137                .await
138                .map(|ak| ak.into())
139                .map_err(|err| ResponseError::new(HttpResponseErrorKind::InvalidRequestResponse.into(), err)),
140            UploadTokenSignerInner::CredentialProvider(UploadTokenCredentialSigner { credential, .. }) => {
141                Ok(credential.async_get(Default::default()).await?.access_key().to_owned())
142            }
143        }
144    }
145
146    #[cfg(feature = "async")]
147    pub(super) async fn async_bucket_name(&self) -> ApiResult<BucketName> {
148        match &self.0 {
149            UploadTokenSignerInner::UploadTokenProvider(provider) => provider
150                .async_bucket_name(Default::default())
151                .await
152                .map_err(|err| ResponseError::new(HttpResponseErrorKind::InvalidRequestResponse.into(), err)),
153            UploadTokenSignerInner::CredentialProvider(UploadTokenCredentialSigner { bucket_name, .. }) => {
154                Ok(bucket_name.to_owned())
155            }
156        }
157    }
158
159    pub(super) fn make_upload_token_provider(
160        &self,
161        object_name: Option<ObjectName>,
162    ) -> OwnedUploadTokenProviderOrReferenced<'_> {
163        match &self.0 {
164            UploadTokenSignerInner::UploadTokenProvider(provider) => {
165                OwnedUploadTokenProviderOrReferenced::Referenced(provider.as_ref())
166            }
167            UploadTokenSignerInner::CredentialProvider(UploadTokenCredentialSigner {
168                credential,
169                bucket_name,
170                lifetime,
171                on_policy_generated,
172            }) => {
173                if let Some(object_name) = object_name {
174                    OwnedUploadTokenProviderOrReferenced::Owned(Box::new(make_object_upload_token_provider(
175                        bucket_name,
176                        object_name,
177                        *lifetime,
178                        credential,
179                        on_policy_generated.to_owned(),
180                    )))
181                } else {
182                    OwnedUploadTokenProviderOrReferenced::Owned(Box::new(make_bucket_upload_token_provider(
183                        bucket_name,
184                        *lifetime,
185                        credential,
186                        on_policy_generated.to_owned(),
187                    )))
188                }
189            }
190        }
191    }
192
193    #[allow(dead_code)]
194    fn assert() {
195        assert_impl!(Send: Self);
196        assert_impl!(Sync: Self);
197    }
198}
199
200pub(super) enum OwnedUploadTokenProviderOrReferenced<'r> {
201    Owned(Box<dyn UploadTokenProvider + 'r>),
202    Referenced(&'r dyn UploadTokenProvider),
203}
204
205impl OwnedUploadTokenProviderOrReferenced<'_> {
206    pub(super) fn as_ref(&self) -> &dyn UploadTokenProvider {
207        match self {
208            OwnedUploadTokenProviderOrReferenced::Owned(provider) => provider.as_ref(),
209            OwnedUploadTokenProviderOrReferenced::Referenced(referenced) => referenced,
210        }
211    }
212}
213
214fn make_object_upload_token_provider<C: CredentialProvider + Clone>(
215    bucket_name: &BucketName,
216    object_name: ObjectName,
217    lifetime: Duration,
218    credential: C,
219    on_policy_generated: Option<OnPolicyGeneratedCallback>,
220) -> ObjectUploadTokenProvider<C> {
221    let mut builder = ObjectUploadTokenProvider::builder(bucket_name.to_owned(), object_name, lifetime, credential);
222    if let Some(on_policy_generated) = on_policy_generated {
223        builder = builder.on_policy_generated(move |builder| on_policy_generated(builder));
224    }
225    builder.build()
226}
227
228fn make_bucket_upload_token_provider<C: CredentialProvider + Clone>(
229    bucket_name: &BucketName,
230    lifetime: Duration,
231    credential: C,
232    on_policy_generated: Option<OnPolicyGeneratedCallback>,
233) -> BucketUploadTokenProvider<C> {
234    let mut builder = BucketUploadTokenProvider::builder(bucket_name.to_owned(), lifetime, credential);
235    if let Some(on_policy_generated) = on_policy_generated {
236        builder = builder.on_policy_generated(move |builder| on_policy_generated(builder));
237    }
238    builder.build()
239}
240
241impl<T: UploadTokenProvider + 'static> From<T> for UploadTokenSigner {
242    #[inline]
243    fn from(upload_token_provider: T) -> Self {
244        Self(UploadTokenSignerInner::UploadTokenProvider(Arc::new(
245            upload_token_provider,
246        )))
247    }
248}
249
250/// 上传凭证签发构建器
251#[derive(Clone, Debug)]
252pub struct UploadTokenSignerBuilder(UploadTokenCredentialSigner);
253
254impl UploadTokenSignerBuilder {
255    /// 根据认证信息提供者和存储空间名称创建上传凭证签发构建器
256    #[inline]
257    pub fn new_credential_provider(
258        credential: impl CredentialProvider + 'static,
259        bucket_name: impl Into<BucketName>,
260        lifetime: Duration,
261    ) -> Self {
262        Self(UploadTokenCredentialSigner {
263            credential: Arc::new(credential),
264            bucket_name: bucket_name.into(),
265            lifetime,
266            on_policy_generated: None,
267        })
268    }
269
270    /// 设置上传凭证回调函数
271    #[inline]
272    #[must_use]
273    pub fn on_policy_generated(
274        mut self,
275        callback: impl Fn(&mut UploadPolicyBuilder) -> AnyResult<()> + Sync + Send + 'static,
276    ) -> Self {
277        self.0.on_policy_generated = Some(Arc::new(callback));
278        self
279    }
280
281    /// 构造存储空间上传凭证
282    #[inline]
283    pub fn build(self) -> UploadTokenSigner {
284        UploadTokenSigner(UploadTokenSignerInner::CredentialProvider(self.0))
285    }
286}