use super::element::TargetType; use super::offscreen_renderer::{CanvasWrapper, OffscreenRenderer}; use crate::{ components::app::{Buffer, FILE_PATH_ROOT}, CONFIG, }; use chrono::{prelude::*, Duration}; use once_cell::sync::Lazy; use regex::Regex; use std::{cell::Ref, collections::HashMap, path::PathBuf}; use tracing::*; static REREMAP: Lazy> = Lazy::new(|| { let mut map = HashMap::new(); map.insert("%Y", r"\d{4}"); map.insert("%m", r"\d{2}"); map.insert("%d", r"\d{2}"); map.insert("%H", r"\d{2}"); map.insert("%M", r"\d{2}"); map.insert("%S", r"\d{2}"); map.insert("{prefix}", r"(.+?)"); map }); #[derive(Debug)] pub struct Dispatcher { datetime: DateTime, fore_len: usize, back_len: usize, step: Duration, } impl Dispatcher { pub fn new(fore_len: usize, back_len: usize, step: Duration) -> Self { Self { datetime: Utc::now(), fore_len, back_len, step, } } pub fn set_current_time(&mut self, datetime: DateTime) { self.datetime = datetime; } pub fn set_step(&mut self, step: Duration) { self.step = step; } pub fn set_fore_len(&mut self, fore_len: usize) { self.fore_len = fore_len; } pub fn set_back_len(&mut self, back_len: usize) { self.back_len = back_len; } pub fn get_single_path( &self, name: &str, current_time: DateTime, check_existed: bool, ) -> Option { let datetime_format: regex::Regex = Regex::new(r"(?:%[YHMSmd](?:[-/:_]?%[YHMSmd])*)").unwrap(); let config = CONFIG.lock().unwrap(); let path_format = config .plugins .get("etws_loader") .unwrap() .path_formats .as_ref(); if path_format.is_none() { return None; } let c = path_format.unwrap().get(name).map(|s| { let path = s.clone(); let need_formated = datetime_format.captures_iter(&path).collect::>(); let mut result_path = path.clone(); for need_format in need_formated.iter() { let fmt = need_format.get(0).unwrap().as_str(); let t = current_time.format(fmt).to_string(); result_path = result_path.replace(fmt, &t); } result_path }); if let Some(c) = c { if check_existed { if std::path::Path::new(&c).exists() { Some(c) } else { None } } else { Some(c) } } else { None } } pub fn get_path( &self, name: &str, current_time: DateTime, check_existed: bool, mut max_retry_time: usize, ) -> Option)>> { let datetime_format: regex::Regex = Regex::new(r"%[YHMSmd](?:[-/:_]?%[YHMSmd])*").unwrap(); let config = CONFIG.lock().unwrap(); let path_format = config .plugins .get("etws_loader") .unwrap() .path_formats .as_ref(); if path_format.is_none() { return None; } path_format.unwrap().get(name).map(|s| { let path = s.clone(); let file_path = { FILE_PATH_ROOT.lock().unwrap().clone() }; let path = if path.starts_with("./") { let file_root = file_root(&file_path, path.replace("./", "")); file_root.map(|root| { let splited = path.split_at(2); root.join(PathBuf::from(splited.1)) }) } else { Some(PathBuf::from(path)) }; let mut result_paths = Vec::new(); if let Some(path_uninit) = path { let mut path_str = path_uninit.to_string_lossy().to_string(); let prefixs = get_prefix(&file_path, &path_str); for (idx, prefix) in prefixs.iter().enumerate() { if let Some(s) = prefix.as_ref() { path_str = path_str.replacen("{prefix}", &s, 1); } } let need_formated = datetime_format.captures_iter(&path_str).collect::>(); let mut fore = self.fore_len; let mut back = 1; while fore > 0 { let mut result_path = path_str.clone(); let t = current_time - self.step * fore as i32; for need_format in need_formated.iter() { let fmt = need_format.get(0).unwrap().as_str(); let t = t.format(fmt).to_string(); result_path = result_path.replace(fmt, &t); } if check_existed { // if max_retry_time == 0 { // break; // } if !std::path::Path::new(&result_path).exists() { } else { result_paths.push((result_path.clone(), t)); } } else { result_paths.push((result_path.clone(), t)); } fore = fore - 1; } while back < self.back_len + 1 { let mut result_path = path_str.clone(); let t = current_time + self.step * back as i32; for need_format in need_formated.iter() { let fmt = need_format.get(0).unwrap().as_str(); let t = t.format(fmt).to_string(); result_path = result_path.replace(fmt, &t); } if check_existed { // if max_retry_time == 0 { // break; // } if !std::path::Path::new(&result_path).exists() { } else { result_paths.push((result_path.clone(), t)); } } else { result_paths.push((result_path.clone(), t)); } back = back + 1; } } result_paths }) } } fn file_root(path: &PathBuf, pat: String) -> Option { let new_pat = rereplace(&pat); let path_str = path.to_string_lossy(); let re = Regex::new(&new_pat).unwrap(); let splited = re.split(&path_str); let splited = splited.collect::>(); if splited.len() == 2 { let root = splited.first().unwrap(); Some(PathBuf::from(root)) } else { None } } fn rereplace(pat: &str) -> String { let mut result = pat.to_string(); for (k, v) in REREMAP.iter() { result = result.replace(k, v); } result } fn get_prefix(path: &PathBuf, pat: &str) -> Vec> { let replaced = rereplace(pat); let path_str = path.to_string_lossy(); let re = Regex::new(&replaced).unwrap(); let prefixs = re.captures(&path_str).unwrap(); let mut prefixs = prefixs.iter().collect::>(); prefixs.remove(0); prefixs .into_iter() .map(|x| x.map(|v| v.as_str().to_string())) .collect() }