use std::fs;
use std::path::Path;
use include_dir::{include_dir, Dir};
use a2ui_base::message_processor::MessageProcessor;
use a2ui_base::protocol::server_to_client::A2uiMessage;
pub static SPEC_DIR: Dir<'static> =
include_dir!("$CARGO_MANIFEST_DIR/a2ui/specification");
pub struct Sample {
pub name: String,
pub description: String,
pub file_path: String,
pub messages: Vec<A2uiMessage>,
}
pub fn load_samples_from_dir(dir: &str) -> Vec<Sample> {
let path = Path::new(dir);
if !path.is_dir() {
return Vec::new();
}
let dir_entries = match fs::read_dir(path) {
Ok(de) => de,
Err(e) => {
eprintln!("Warning: cannot read sample directory {:?}: {}", dir, e);
return Vec::new();
}
};
let mut entries: Vec<String> = dir_entries
.filter_map(|entry| {
let entry = entry.ok()?;
let file_name = entry.file_name().to_string_lossy().to_string();
if file_name.ends_with(".json") {
Some(file_name)
} else {
None
}
})
.collect();
entries.sort();
let mut samples = Vec::new();
for file_name in &entries {
let full_path = path.join(file_name);
let content = match fs::read_to_string(&full_path) {
Ok(c) => c,
Err(e) => {
eprintln!("Warning: cannot read {:?}: {}", full_path, e);
continue;
}
};
match MessageProcessor::load_sample(&content) {
Ok((name, description, messages)) => {
samples.push(Sample {
name,
description,
file_path: file_name.clone(),
messages,
});
}
Err(e) => {
eprintln!(
"Warning: failed to parse sample {:?}: {}",
full_path, e
);
}
}
}
samples
}
pub fn load_samples(subpath: &str) -> Vec<Sample> {
let dir = match SPEC_DIR.get_dir(subpath) {
Some(d) => d,
None => {
eprintln!("Warning: embedded sample directory not found: {subpath:?}");
return Vec::new();
}
};
let mut files: Vec<&include_dir::File> = dir.files().collect();
files.sort_by_key(|f| f.path().to_string_lossy().to_string());
files.retain(|f| f.path().extension().is_some_and(|ext| ext == "json"));
let mut samples = Vec::new();
for file in files {
let file_name = file
.path()
.file_name()
.map(|n| n.to_string_lossy().to_string())
.unwrap_or_default();
let content = match std::str::from_utf8(file.contents()) {
Ok(s) => s,
Err(e) => {
eprintln!("Warning: sample {file_name:?} is not valid UTF-8: {e}");
continue;
}
};
match MessageProcessor::load_sample(content) {
Ok((name, description, messages)) => samples.push(Sample {
name,
description,
file_path: file_name,
messages,
}),
Err(e) => {
eprintln!("Warning: failed to parse sample {file_name:?}: {e}");
}
}
}
samples
}