use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::thread;
use super::assets::load_studio_bundle;
use super::kicad_sync::evaluate;
use super::pipeline::execute_pipeline;
use super::state::{Health, Slot, State};
pub(super) fn load_bundle(state: &State) {
if let Ok(mut lock) = state.bundle.lock() {
if cfg!(debug_assertions) || lock.is_none() {
*lock = load_studio_bundle();
}
}
}
pub(super) fn warn_if_bundle_missing(state: &State) {
if state.bundle.lock().is_ok_and(|bundle| bundle.is_none()) {
eprintln!(
"⚠ This fusible build has no studio bundle: schematic, PCB and 3D fall back to native previews. \
Install a GitHub release binary, or run `bun install && bun run build` in studio/ and rebuild."
);
}
}
pub(super) fn refresh(slot: &Slot, state: &State) {
let start = std::time::Instant::now();
let (payload, source) = execute_pipeline(&slot.entry);
let shared: Option<Arc<str>> = source.as_deref().map(Arc::from);
let health = Health {
fuse_blown: payload.fuse_blown,
violations: payload.diagnostics.len(),
};
slot.body
.update(source, payload.revision.clone(), slot.name.clone());
if let Ok(json_str) = serde_json::to_string(&payload) {
slot.publish(json_str.clone(), health, shared);
state.hub.broadcast(&json_str);
println!("✓ Circuit updated in {:.1}s", start.elapsed().as_secs_f32());
}
evaluate(slot, state);
load_bundle(state);
}
pub(super) fn watch_dir(entry: &Path) -> PathBuf {
if entry.is_dir() {
return entry.to_path_buf();
}
entry
.parent()
.unwrap_or_else(|| Path::new("."))
.to_path_buf()
}
pub(super) fn rebuild_trigger(slot: Slot, state: State) -> impl FnMut() + Send + 'static {
let rebuilding = Arc::new(AtomicBool::new(false));
let pending = Arc::new(AtomicBool::new(false));
move || {
pending.store(true, Ordering::SeqCst);
if rebuilding.swap(true, Ordering::SeqCst) {
return;
}
let (slot, state) = (slot.clone(), state.clone());
let (rebuilding, pending) = (rebuilding.clone(), pending.clone());
thread::spawn(move || loop {
while pending.swap(false, Ordering::SeqCst) {
println!("🔄 File change detected — rebuilding circuit preview...");
refresh(&slot, &state);
}
rebuilding.store(false, Ordering::SeqCst);
if !pending.load(Ordering::SeqCst) || rebuilding.swap(true, Ordering::SeqCst) {
break;
}
});
}
}