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#[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 #[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 #[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 #[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 #[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 #[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#[derive(Clone, Debug)]
252pub struct UploadTokenSignerBuilder(UploadTokenCredentialSigner);
253
254impl UploadTokenSignerBuilder {
255 #[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 #[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 #[inline]
283 pub fn build(self) -> UploadTokenSigner {
284 UploadTokenSigner(UploadTokenSignerInner::CredentialProvider(self.0))
285 }
286}