use crate::{
ConnectionStatus, Error, ErrorKind, auth::AuthProvider, internal_rpc::InternalRPCHandle,
killswitch::KillSwitch,
};
use async_rs::{Runtime, traits::*};
use std::{fmt, sync::Arc, time::Duration};
use tracing::error;
pub struct SecretUpdate<RK: RuntimeKit + Clone + Send + 'static> {
connection_status: ConnectionStatus,
runtime: Runtime<RK>,
provider: Arc<dyn AuthProvider>,
killswitch: KillSwitch,
}
impl<RK: RuntimeKit + Clone + Send + 'static> Clone for SecretUpdate<RK> {
fn clone(&self) -> Self {
Self {
connection_status: self.connection_status.clone(),
runtime: self.runtime.clone(),
provider: self.provider.clone(),
killswitch: self.killswitch.clone(),
}
}
}
impl<RK: RuntimeKit + Clone + Send + 'static> SecretUpdate<RK> {
pub(crate) fn new(
connection_status: ConnectionStatus,
runtime: Runtime<RK>,
provider: Arc<dyn AuthProvider>,
) -> Self {
Self {
connection_status,
runtime,
provider,
killswitch: KillSwitch::default(),
}
}
pub(crate) fn start(&self, internal_rpc: InternalRPCHandle) {
let secret_update = self.clone();
let killswitch = self.killswitch.clone();
self.runtime.spawn(async move {
while let Some(dur) = secret_update.poll_timeout(&killswitch) {
secret_update.runtime.sleep(dur).await;
match secret_update
.provider
.refresh()
.map_err(|e| Error::from(ErrorKind::AuthProviderError(e)))
{
Err(err) => error!(%err, "Failed refreshing secret"),
Ok(token) => {
if let Err(err) = internal_rpc
.update_secret(token, "Automatic periodical refresh".into())
.await
{
error!(%err, "Failed refreshing secret");
}
}
}
}
});
}
pub(crate) fn cancel(&self) {
self.killswitch.kill();
}
pub(crate) fn reset(&mut self) {
self.cancel();
self.killswitch = KillSwitch::default();
}
fn poll_timeout(&self, killswitch: &KillSwitch) -> Option<Duration> {
if killswitch.killed() || !self.connection_status.connected() {
return None;
}
self.provider.valid_for()
}
}
impl<RK: RuntimeKit + Clone + Send + 'static> fmt::Debug for SecretUpdate<RK> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SecretUpdate").finish()
}
}