use std::path::Path;
use jellyflow_core::core::{Graph, GraphId};
use serde::{Deserialize, Serialize};
pub const GRAPH_FILE_VERSION: u32 = 1;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GraphFileV1 {
pub graph_id: GraphId,
pub graph_version: u32,
pub graph: Graph,
}
impl GraphFileV1 {
pub fn from_graph(graph: Graph) -> Self {
Self {
graph_id: graph.graph_id,
graph_version: GRAPH_FILE_VERSION,
graph,
}
}
pub fn validate(&self) -> Result<(), GraphFileError> {
if self.graph_id != self.graph.graph_id {
return Err(GraphFileError::InconsistentGraphId);
}
Ok(())
}
pub fn load_json(path: impl AsRef<Path>) -> Result<Self, GraphFileError> {
let path = path.as_ref();
let bytes = std::fs::read(path).map_err(|source| GraphFileError::Read {
path: path.display().to_string(),
source,
})?;
let v = serde_json::from_slice::<Self>(&bytes).map_err(|source| GraphFileError::Parse {
path: path.display().to_string(),
source,
})?;
v.validate()?;
Ok(v)
}
pub fn load_json_if_exists(path: impl AsRef<Path>) -> Result<Option<Self>, GraphFileError> {
let path = path.as_ref();
if !path.exists() {
return Ok(None);
}
Self::load_json(path).map(Some)
}
pub fn save_json(&self, path: impl AsRef<Path>) -> Result<(), GraphFileError> {
let path = path.as_ref();
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent).map_err(|source| GraphFileError::Write {
path: path.display().to_string(),
source,
})?;
}
let bytes =
serde_json::to_vec_pretty(self).map_err(|source| GraphFileError::Serialize {
path: path.display().to_string(),
source,
})?;
std::fs::write(path, bytes).map_err(|source| GraphFileError::Write {
path: path.display().to_string(),
source,
})
}
}
#[derive(Debug, thiserror::Error)]
pub enum GraphFileError {
#[error("failed to read graph file: {path}")]
Read {
path: String,
source: std::io::Error,
},
#[error("failed to parse graph file JSON: {path}")]
Parse {
path: String,
source: serde_json::Error,
},
#[error("failed to write graph file: {path}")]
Write {
path: String,
source: std::io::Error,
},
#[error("failed to serialize graph file JSON: {path}")]
Serialize {
path: String,
source: serde_json::Error,
},
#[error("graph file wrapper graph_id does not match graph.graph_id")]
InconsistentGraphId,
}