use std::sync::Arc;
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
#[derive(Debug, Clone)]
pub struct CountingKeys {
inner: asx::KeyPair,
chain: Vec<asx::Certificate>,
signs: Arc<AtomicUsize>,
decrypts: Arc<AtomicUsize>,
failing: Arc<AtomicBool>,
}
impl CountingKeys {
pub fn new(pair: &super::pki::KeyPair) -> CountingKeys {
CountingKeys {
inner: pair.key_pair(),
chain: vec![pair.certificate()],
signs: Arc::default(),
decrypts: Arc::default(),
failing: Arc::default(),
}
}
pub fn signs(&self) -> usize {
self.signs.load(Ordering::SeqCst)
}
pub fn decrypts(&self) -> usize {
self.decrypts.load(Ordering::SeqCst)
}
pub fn fail(&self) {
self.failing.store(true, Ordering::SeqCst);
}
}
impl asx::Signer for CountingKeys {
fn certificate_chain(&self) -> &[asx::Certificate] {
&self.chain
}
fn sign<'a>(
&'a self,
algorithm: asx::SignatureAlgorithm,
message: &'a [u8],
) -> asx::BoxFuture<'a, Result<Vec<u8>, Box<dyn std::error::Error + Send + Sync>>> {
Box::pin(async move {
if self.failing.load(Ordering::SeqCst) {
return Err("the signing service is unavailable".into());
}
self.signs.fetch_add(1, Ordering::SeqCst);
tokio::task::yield_now().await;
asx::Signer::sign(&self.inner, algorithm, message).await
})
}
}
impl asx::Decrypter for CountingKeys {
fn certificate(&self) -> &asx::Certificate {
&self.chain[0]
}
fn decrypt<'a>(
&'a self,
operation: asx::KeyOp<'a>,
) -> asx::BoxFuture<
'a,
Result<zeroize::Zeroizing<Vec<u8>>, Box<dyn std::error::Error + Send + Sync>>,
> {
Box::pin(async move {
if self.failing.load(Ordering::SeqCst) {
return Err("the decryption service is unavailable".into());
}
self.decrypts.fetch_add(1, Ordering::SeqCst);
tokio::task::yield_now().await;
asx::Decrypter::decrypt(&self.inner, operation).await
})
}
}