1use crate::{Context, ProvideCredential, Result, SignRequest, SigningCredential};
19use std::sync::{Arc, Mutex};
20use std::time::Duration;
21
22#[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 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 pub fn with_context(mut self, ctx: Context) -> Self {
49 self.ctx = ctx;
50 self
51 }
52
53 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)); self
61 }
62
63 pub fn with_request_signer(mut self, signer: impl SignRequest<Credential = K>) -> Self {
65 self.builder = Arc::new(signer);
66 self
67 }
68
69 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}