reqsign_core/
signer.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use crate::{Context, ProvideCredential, Result, SignRequest, SigningCredential};
19use std::sync::{Arc, Mutex};
20use std::time::Duration;
21
22/// Signer is the main struct used to sign the request.
23#[derive(Clone, Debug)]
24pub struct Signer<K: SigningCredential> {
25    ctx: Context,
26    loader: Arc<dyn ProvideCredential<Credential = K>>,
27    builder: Arc<dyn SignRequest<Credential = K>>,
28    credential: Arc<Mutex<Option<K>>>,
29}
30
31impl<K: SigningCredential> Signer<K> {
32    /// Create a new signer.
33    pub fn new(
34        ctx: Context,
35        loader: impl ProvideCredential<Credential = K>,
36        builder: impl SignRequest<Credential = K>,
37    ) -> Self {
38        Self {
39            ctx,
40
41            loader: Arc::new(loader),
42            builder: Arc::new(builder),
43            credential: Arc::new(Mutex::new(None)),
44        }
45    }
46
47    /// Replace the context while keeping credential provider and request signer.
48    pub fn with_context(mut self, ctx: Context) -> Self {
49        self.ctx = ctx;
50        self
51    }
52
53    /// Replace the credential provider while keeping context and request signer.
54    pub fn with_credential_provider(
55        mut self,
56        provider: impl ProvideCredential<Credential = K>,
57    ) -> Self {
58        self.loader = Arc::new(provider);
59        self.credential = Arc::new(Mutex::new(None)); // Clear cached credential
60        self
61    }
62
63    /// Replace the request signer while keeping context and credential provider.
64    pub fn with_request_signer(mut self, signer: impl SignRequest<Credential = K>) -> Self {
65        self.builder = Arc::new(signer);
66        self
67    }
68
69    /// Signing request.
70    pub async fn sign(
71        &self,
72        req: &mut http::request::Parts,
73        expires_in: Option<Duration>,
74    ) -> Result<()> {
75        let credential = self.credential.lock().expect("lock poisoned").clone();
76        let credential = if credential.is_valid() {
77            credential
78        } else {
79            let ctx = self.loader.provide_credential(&self.ctx).await?;
80            *self.credential.lock().expect("lock poisoned") = ctx.clone();
81            ctx
82        };
83
84        self.builder
85            .sign_request(&self.ctx, req, credential.as_ref(), expires_in)
86            .await
87    }
88}