use super::*;
use std::path::PathBuf;
pub(crate) fn write_json_blob(log: &mut EventLog, value: Value) -> Result<WorkflowOutputRef> {
let bytes = serde_json::to_vec(&value)?;
let hash = sha256_hex(&bytes);
let path = PathBuf::from(&log.blob_dir).join(&hash);
std::fs::write(&path, &bytes)?;
Ok(WorkflowOutputRef {
output_hash: format!("sha256:{hash}"),
output_path: path.display().to_string(),
output_bytes: bytes.len(),
output_schema_version: 1,
content_type: Some("application/json".to_string()),
})
}
pub(crate) fn sha256_hex(bytes: &[u8]) -> String {
let mut hasher = Sha256::new();
hasher.update(bytes);
lower_hex(&hasher.finalize())
}
pub(crate) fn lower_hex(bytes: &[u8]) -> String {
const HEX: &[u8; 16] = b"0123456789abcdef";
let mut out = String::with_capacity(bytes.len() * 2);
for byte in bytes {
out.push(HEX[(byte >> 4) as usize] as char);
out.push(HEX[(byte & 0x0f) as usize] as char);
}
out
}
pub(crate) fn expand_tilde(path: &str) -> String {
if !path.starts_with('~') {
return path.to_string();
}
let home = match std::env::var("HOME") {
Ok(home) => home,
Err(_) => return path.to_string(),
};
if path.len() == 1 {
return home;
}
if path.starts_with("~/") {
return home + &path[1..];
}
path.to_string()
}
pub(crate) fn is_retryable_feishu_resume_error(err: &anyhow::Error) -> bool {
if let Some(reqwest_err) = err.downcast_ref::<reqwest::Error>() {
if reqwest_err.is_timeout() || reqwest_err.is_connect() {
return true;
}
}
let haystacks = err
.chain()
.map(|cause| cause.to_string().to_ascii_lowercase())
.collect::<Vec<_>>();
let needles = [
"429",
"rate limit",
"too many requests",
"timeout",
"timed out",
"temporarily unavailable",
"service unavailable",
"connection reset",
"connection refused",
"network error",
"retry later",
"unavailable",
];
haystacks
.iter()
.any(|text| needles.iter().any(|needle| text.contains(needle)))
}