use miette::{miette, Diagnostic}; use thiserror::Error; use super::Initiator; use crate::initiators::InitiatorCallbacks; use crate::resources::modules::fabaccess::Status; use crate::session::SessionHandle; use async_io::Timer; use futures_util::future::BoxFuture; use futures_util::ready; use std::collections::HashMap; use std::future::Future; use std::pin::Pin; use std::task::{Context, Poll}; use std::time::{Duration, Instant}; pub struct Dummy { callbacks: InitiatorCallbacks, session: SessionHandle, state: DummyState, } enum DummyState { Empty, Sleeping(Timer, Option), Updating(BoxFuture<'static, Status>), } impl Dummy { fn timer() -> Timer { Timer::after(Duration::from_secs(2)) } fn flip(&self, status: Status) -> BoxFuture<'static, Status> { let session = self.session.clone(); let mut callbacks = self.callbacks.clone(); Box::pin(async move { let next = match &status { Status::Free => Status::InUse(session.get_user_ref()), Status::InUse(_) => Status::Free, _ => Status::Free, }; callbacks.try_update(session, status).await; next }) } } #[derive(Debug, Error, Diagnostic)] pub enum DummyError {} impl Future for Dummy { type Output = (); fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { let span = tracing::debug_span!("Dummy initiator poll"); let _guard = span.enter(); tracing::trace!("polling Dummy initiator"); loop { match &mut self.state { DummyState::Empty => { tracing::trace!("Dummy initiator is empty, initializing…"); self.state = DummyState::Sleeping(Self::timer(), Some(Status::Free)); } DummyState::Sleeping(timer, next) => { tracing::trace!("Sleep timer exists, polling it."); let _: Instant = ready!(Pin::new(timer).poll(cx)); tracing::trace!("Timer has fired, poking out an update!"); let status = next.take().unwrap(); let f = self.flip(status); self.state = DummyState::Updating(f); } DummyState::Updating(f) => { tracing::trace!("Update future exists, polling it ."); let next = ready!(Pin::new(f).poll(cx)); tracing::trace!("Update future completed, sleeping!"); self.state = DummyState::Sleeping(Self::timer(), Some(next)); } } } } } impl Initiator for Dummy { fn new(params: &HashMap, callbacks: InitiatorCallbacks) -> miette::Result where Self: Sized, { let uid = params .get("uid") .ok_or_else(|| miette!("Dummy initiator configured without an UID"))?; let session = callbacks .open_session(uid) .ok_or_else(|| miette!("The configured user for the dummy initiator does not exist"))?; Ok(Self { callbacks, session, state: DummyState::Empty, }) } }