use std::collections::BTreeMap;
use std::path::{Path, PathBuf};
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use time::OffsetDateTime;
use argonauts_core::events::run::Party;
use super::Candidate;
use crate::error::Result;
use crate::types::RunRecord;
pub const CANDIDATES: &str = "candidates.json";
pub const CANARIES: &str = "canaries.json";
pub const LEARNED_WORKFLOWS: &str = "learned_workflows.json";
pub const SPEND: &str = "spend.json";
pub const CANDIDATE_DIRS: &str = "candidates";
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Canary {
pub learned_workflow: String,
pub candidate: String,
pub version: u32,
pub parent: u32,
#[serde(with = "time::serde::rfc3339")]
pub started: OffsetDateTime,
pub by: Party,
pub runs: Vec<RunRecord>,
}
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
pub struct LearnedWorkflowState {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub pointer: Option<Pointer>,
#[serde(default, with = "time::serde::rfc3339::option")]
pub last_promoted: Option<OffsetDateTime>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Pointer {
pub version: u32,
pub checkout_was: Option<u32>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Spend {
#[serde(with = "time::serde::rfc3339")]
pub at: OffsetDateTime,
pub candidate: String,
pub usd: f64,
}
pub type Candidates = Vec<Candidate>;
pub type Canaries = BTreeMap<String, Canary>;
pub type LearnedWorkflows = BTreeMap<String, LearnedWorkflowState>;
pub type Ledger = Vec<Spend>;
pub fn read<T: DeserializeOwned + Default>(path: &Path) -> Result<T> {
if !path.is_file() {
return Ok(T::default());
}
let text = std::fs::read_to_string(path)?;
Ok(serde_json::from_str(&text)?)
}
pub fn write<T: Serialize>(path: &Path, value: &T) -> Result<()> {
if let Some(dir) = path.parent() {
std::fs::create_dir_all(dir)?;
}
let temporary = temporary_beside(path);
std::fs::write(&temporary, serde_json::to_string_pretty(value)?)?;
std::fs::rename(&temporary, path)?;
Ok(())
}
fn temporary_beside(path: &Path) -> PathBuf {
let mut name = path.file_name().unwrap_or_default().to_os_string();
name.push(".tmp");
path.with_file_name(name)
}