mirror of
https://github.com/euzu/tuliprox.git
synced 2026-10-06 07:52:18 +02:00
100 lines
3.4 KiB
Rust
100 lines
3.4 KiB
Rust
use std::collections::HashMap;
|
|
use std::fs;
|
|
use std::path::{Path, PathBuf};
|
|
use serde::{Deserialize, Serialize};
|
|
use std::time::{SystemTime, UNIX_EPOCH};
|
|
use log::{error, warn};
|
|
use shared::concat_string;
|
|
use crate::repository::storage::{get_input_storage_path, sanitize_name};
|
|
|
|
pub const STATUS_FILE: &str = "status.json";
|
|
|
|
#[derive(Serialize, Deserialize, Default, Debug, Clone, PartialEq)]
|
|
pub enum ClusterState {
|
|
#[default]
|
|
Ok,
|
|
Failed,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
pub struct ClusterStatus {
|
|
pub status: ClusterState,
|
|
pub timestamp: u64,
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Default, Clone)]
|
|
pub struct InputStatus {
|
|
#[serde(default)]
|
|
pub clusters: HashMap<String, ClusterStatus>,
|
|
}
|
|
|
|
pub fn resolve_input_storage_path(working_dir: &str, input_name: &str) -> PathBuf {
|
|
if let Ok(path) = get_input_storage_path(input_name, working_dir) { path } else {
|
|
let sanitized_name: String = sanitize_name(input_name);
|
|
let name = concat_string!(cap = 6 + sanitized_name.len(); "input_", &sanitized_name);
|
|
Path::new(working_dir).join(name)
|
|
}
|
|
}
|
|
|
|
pub fn load_input_status(path: &Path) -> InputStatus {
|
|
let status_path = path.join(STATUS_FILE);
|
|
if status_path.exists() {
|
|
match fs::read_to_string(&status_path) {
|
|
Ok(content) => match serde_json::from_str(&content) {
|
|
Ok(status) => return status,
|
|
Err(e) => warn!("Failed to parse input status file {}: {e}", status_path.display()),
|
|
},
|
|
Err(e) => warn!("Failed to read input status file {}: {e}", status_path.display()),
|
|
}
|
|
}
|
|
InputStatus::default()
|
|
}
|
|
|
|
pub fn save_input_status(path: &Path, status: &InputStatus) {
|
|
let status_path = path.join(STATUS_FILE);
|
|
if let Some(parent) = status_path.parent() {
|
|
if let Err(e) = fs::create_dir_all(parent) {
|
|
error!("Failed to create input storage directory {}: {e}", parent.display());
|
|
return;
|
|
}
|
|
}
|
|
match serde_json::to_string_pretty(status) {
|
|
Ok(content) => {
|
|
if let Err(e) = fs::write(&status_path, content) {
|
|
error!("Failed to write input status file {}: {e}", status_path.display());
|
|
}
|
|
},
|
|
Err(e) => error!("Failed to serialize input status: {e}"),
|
|
}
|
|
}
|
|
|
|
pub fn is_cache_valid(status: &InputStatus, cluster: &str, cache_duration_seconds: u64) -> bool {
|
|
if cache_duration_seconds == 0 {
|
|
return false;
|
|
}
|
|
if let Some(cluster_status) = status.clusters.get(cluster) {
|
|
if cluster_status.status != ClusterState::Ok {
|
|
return false;
|
|
}
|
|
let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap_or_default().as_secs();
|
|
if now > cluster_status.timestamp {
|
|
// check if age is within duration
|
|
// timestamp is creation time.
|
|
// wait, assuming timestamp is Last Update Time.
|
|
// now - timestamp < duration
|
|
return now - cluster_status.timestamp < cache_duration_seconds;
|
|
}
|
|
// Timestamp in future? Invalid.
|
|
return false;
|
|
}
|
|
false
|
|
}
|
|
|
|
pub fn update_cluster_status(status: &mut InputStatus, cluster: &str, state: ClusterState) {
|
|
let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap_or_default().as_secs();
|
|
status.clusters.insert(cluster.to_string(), ClusterStatus {
|
|
status: state,
|
|
timestamp: now,
|
|
});
|
|
}
|