fabaccess-bffh/bffhd/initiators/mod.rs

150 lines
4.3 KiB
Rust
Raw Permalink Normal View History

2022-06-07 14:05:46 +02:00
use crate::initiators::dummy::Dummy;
use crate::resources::modules::fabaccess::Status;
use crate::session::SessionHandle;
use crate::{
AuthenticationHandle, Config, MachineState, Resource, ResourcesHandle, SessionManager,
};
use async_compat::CompatExt;
use executor::prelude::Executor;
use futures_util::ready;
use miette::IntoDiagnostic;
use rumqttc::ConnectReturnCode::Success;
use rumqttc::{AsyncClient, ConnectionError, Event, Incoming, MqttOptions};
use std::collections::HashMap;
use std::fmt::Display;
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
2022-06-07 14:05:46 +02:00
use std::time::Duration;
use url::Url;
2021-12-17 16:43:31 +01:00
2022-06-07 14:05:46 +02:00
mod dummy;
2021-12-17 16:43:31 +01:00
2022-06-07 14:05:46 +02:00
pub trait Initiator: Future<Output = ()> {
fn new(params: &HashMap<String, String>, callbacks: InitiatorCallbacks) -> miette::Result<Self>
where
Self: Sized;
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<()> {
<Self as Future>::poll(self, cx)
}
2021-12-17 16:43:31 +01:00
}
#[derive(Clone)]
2022-06-07 14:05:46 +02:00
pub struct InitiatorCallbacks {
resource: Resource,
sessions: SessionManager,
}
2022-06-07 14:05:46 +02:00
impl InitiatorCallbacks {
pub fn new(resource: Resource, sessions: SessionManager) -> Self {
Self { resource, sessions }
2021-12-17 16:43:31 +01:00
}
2022-06-07 14:05:46 +02:00
pub async fn try_update(&mut self, session: SessionHandle, status: Status) {
self.resource.try_update(session, status).await
}
2022-06-07 14:05:46 +02:00
pub fn open_session(&self, uid: &str) -> Option<SessionHandle> {
self.sessions.open(uid)
}
}
2022-06-07 14:05:46 +02:00
pub struct InitiatorDriver {
name: String,
initiator: Box<dyn Initiator + Unpin + Send>,
}
2022-06-07 14:05:46 +02:00
impl InitiatorDriver {
pub fn new<I>(
name: String,
params: &HashMap<String, String>,
resource: Resource,
sessions: SessionManager,
) -> miette::Result<Self>
where
I: 'static + Initiator + Unpin + Send,
{
let callbacks = InitiatorCallbacks::new(resource, sessions);
let initiator = Box::new(I::new(params, callbacks)?);
Ok(Self { name, initiator })
}
}
2022-06-07 14:05:46 +02:00
impl Future for InitiatorDriver {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
2022-06-07 14:05:46 +02:00
let _guard = tracing::info_span!("initiator poll", initiator=%self.name);
tracing::trace!(initiator=%self.name, "polling initiator");
2022-06-07 14:05:46 +02:00
ready!(Pin::new(&mut self.initiator).poll(cx));
2022-06-07 14:05:46 +02:00
tracing::warn!(initiator=%self.name, "an initiator module ran to completion!");
Poll::Ready(())
}
2022-06-07 14:05:46 +02:00
}
pub fn load(
executor: Executor,
config: &Config,
resources: ResourcesHandle,
sessions: SessionManager,
authentication: AuthenticationHandle,
) -> miette::Result<()> {
let span = tracing::info_span!("loading initiators");
let _guard = span.enter();
let mut initiator_map: HashMap<String, Resource> = config
.init_connections
.iter()
.filter_map(|(k, v)| {
if let Some(resource) = resources.get_by_id(v) {
Some((k.clone(), resource.clone()))
} else {
tracing::error!(initiator=%k, machine=%v,
"Machine configured for initiator not found!");
None
}
})
.collect();
for (name, cfg) in config.initiators.iter() {
if let Some(resource) = initiator_map.remove(name) {
if let Some(driver) = load_single(name, &cfg.module, &cfg.params, resource, &sessions) {
tracing::debug!(module_name=%cfg.module, %name, "starting initiator task");
executor.spawn(driver);
} else {
tracing::error!(module_name=%cfg.module, %name, "Initiator module could not be configured");
}
} else {
tracing::warn!(actor=%name, ?config, "Initiator has no machine configured. Skipping!");
}
}
Ok(())
}
fn load_single(
name: &String,
module_name: &String,
params: &HashMap<String, String>,
resource: Resource,
sessions: &SessionManager,
) -> Option<InitiatorDriver> {
tracing::info!(%name, %module_name, ?params, "Loading initiator");
let o = match module_name.as_ref() {
"Dummy" => Some(InitiatorDriver::new::<Dummy>(
name.clone(),
params,
resource,
sessions.clone(),
)),
_ => None,
};
o.transpose().unwrap_or_else(|error| {
tracing::error!(%error, "failed to configure initiator");
None
})
}