use chrono::Utc; use karlcommon::{Condition, Schedule}; use log::{info, warn}; use crate::{ condition::{ConditionFind, Direction}, TASKS, }; pub fn schedule_dynamic() { info!("starting dynamic scheduling"); let mut tasks = TASKS.write().unwrap(); let mut colliders = vec![]; let mut dynamic = vec![]; for t in tasks.values_mut() { if t.schedule.is_dynamic() { dynamic.push(t) } else { colliders.push(t) } } dynamic.sort_by_key(|t| { if let Schedule::Dynamic { priority, .. } = t.schedule { // TODO increase precision by using floats (priority * 1000.0) as i64 } else { 0 } }); let now = Utc::now().naive_local(); while let Some(t) = dynamic.pop() { let props = match &t.schedule { Schedule::Dynamic { duration, condition, priority, scheduled, } => (duration, condition, priority, scheduled), _ => unreachable!(), }; let duration = chrono::Duration::from_std(std::time::Duration::from_secs(*props.0 as u64)).unwrap(); let cond = Condition::Invert(box Condition::Or( colliders .iter() .map(|c| match &c.schedule { Schedule::Never => Condition::Never, Schedule::Condition(c) => c.clone(), Schedule::Static(r) => Condition::Range { min: r.start, max: r.end, modulus: None, prop: karlcommon::Property::Unix, }, Schedule::Dynamic { scheduled, .. } => match scheduled { Some(r) => Condition::Range { min: r.start, max: r.end, modulus: None, prop: karlcommon::Property::Unix, }, None => Condition::Never, }, }) .collect(), )); let mut cursor = now; let mut found_spot = false; for _ in 0..256 { // TODO actually respect the condition and repeat let free = cond.find_instance(Direction::Forward, cursor); let p_start = free.start.unwrap_or(now); let p_end = p_start + duration; if free.end.map(|e| e >= p_end).unwrap_or(true) { t.schedule = Schedule::Dynamic { condition: props.1.clone(), duration: *props.0, priority: *props.2, scheduled: Some(p_start.timestamp()..p_end.timestamp()), }; colliders.push(t); found_spot = true; break; } cursor = free.end.unwrap() } if !found_spot { warn!("could not find a spot where the task fits in"); } } drop(tasks); info!("done"); }