use std::{fmt::Debug, marker::PhantomData, time::Duration};
use kube::{ResourceExt, api::PostParams};
use staircase::{
controller::{Mutable, MutableStepOutcome, MutableStepResult, RunContext, Step},
resources::{ApiResource, ComponentizedResource, NamedResource, ResourceGenerator},
util::get_opt_by_name,
};
use crate::{
crd::Elevator,
r#gen::{DATA_INDEX_HTML, FLOOR_FILE},
graphics::{elevator_ascii, html_body},
resources::ElevatorPage,
steps::StepError,
};
#[derive(Default)]
pub struct CreateResource<T> {
_dummy: PhantomData<T>,
}
pub struct UpdateConfigmap {}
impl<T> Step for CreateResource<T>
where
T: ComponentizedResource + Sync,
T::Resource: serde::Serialize + Send + Sync,
Elevator: ApiResource<T>,
Elevator: ResourceGenerator<T, GenConfig: Default, Error: Debug>,
Elevator: NamedResource<T>,
{
type Error = StepError;
type InData = ();
type Mode = Mutable;
type OutData = ();
type Resource = Elevator;
async fn run(
&self,
context: &RunContext<Self::Resource>,
data: Self::InData,
) -> MutableStepResult<Self::Resource, Self::OutData, Self::Error> {
if get_opt_by_name::<_, T>(context.resource.as_ref(), &context.client)
.await?
.is_none()
{
let res = ResourceGenerator::<T>::generate(context.resource.as_ref(), Default::default()).unwrap();
let api = ApiResource::<T>::api(context.resource.as_ref(), context.client.clone());
api.create(&PostParams::default(), &res).await?;
Ok(MutableStepOutcome::Modified { status: None })
} else {
Ok(MutableStepOutcome::NoModification { data })
}
}
}
impl Step for UpdateConfigmap {
type Error = StepError;
type InData = ();
type Mode = Mutable;
type OutData = ();
type Resource = Elevator;
async fn run(
&self,
context: &RunContext<Self::Resource>,
data: Self::InData,
) -> MutableStepResult<Self::Resource, Self::OutData, Self::Error> {
match get_opt_by_name::<_, ElevatorPage>(context.resource.as_ref(), &context.client).await? {
Some(mut configmap) => {
let cdata = configmap.data.as_mut().expect("data should exist always");
let floor_cnt = cdata.get(FLOOR_FILE).expect("floor file should exist always");
let floor: i8 = floor_cnt.parse::<i8>().unwrap_or(0);
if floor != context.resource.spec.floor {
tokio::time::sleep(Duration::from_millis(2000)).await;
let new_floor = if context.resource.spec.floor > floor {
floor + 1
} else {
floor - 1
};
let page = html_body(&elevator_ascii(-2, 10, new_floor, &context.resource.spec.content));
{
let data_index = cdata.get_mut(DATA_INDEX_HTML).expect("index.html should exist always");
*data_index = page;
}
{
let floor_cnt = cdata.get_mut(FLOOR_FILE).expect("floor file should exist always");
*floor_cnt = new_floor.to_string();
}
let api = ApiResource::<ElevatorPage>::api(context.resource.as_ref(), context.client.clone());
api.replace(&configmap.name_any(), &PostParams::default(), &configmap)
.await?;
Ok(MutableStepOutcome::Modified { status: None })
} else {
Ok(MutableStepOutcome::NoModification { data })
}
},
None => {
let res = ResourceGenerator::<ElevatorPage>::generate(context.resource.as_ref(), ()).unwrap();
let api = ApiResource::<ElevatorPage>::api(context.resource.as_ref(), context.client.clone());
api.create(&PostParams::default(), &res).await?;
Ok(MutableStepOutcome::Modified { status: None })
},
}
}
}