use std::{path::Path, sync::mpsc::channel, time::Duration};
use anyhow::{Context, Result};
use notify::{Config, Event, EventKind, RecommendedWatcher, RecursiveMode, Watcher};
use tracing::{error, info};
pub async fn run(schema: &str, port: u16) -> Result<()> {
info!("Starting development server");
println!("🚀 FraiseQL Dev Server");
println!(" Schema: {schema}");
println!(" Port: {port} (GraphQL server integration coming soon)");
println!(" Watching for changes...\n");
let schema_path = Path::new(schema);
if !schema_path.exists() {
anyhow::bail!("Schema file not found: {schema}");
}
println!("📦 Initial compilation:");
match compile_schema(schema).await {
Ok(()) => println!(" ✓ Schema compiled successfully\n"),
Err(e) => {
error!("Initial compilation failed: {e}");
println!(" ❌ Compilation failed: {e}\n");
println!(" Fix errors and save to retry...\n");
},
}
let (tx, rx) = channel();
let mut watcher = RecommendedWatcher::new(
move |res: Result<Event, notify::Error>| {
if let Ok(event) = res {
let _ = tx.send(event);
}
},
Config::default(),
)
.context("Failed to create file watcher")?;
watcher
.watch(schema_path, RecursiveMode::NonRecursive)
.context("Failed to watch schema file")?;
loop {
match rx.recv() {
Ok(event) => {
if matches!(event.kind, EventKind::Modify(_)) {
info!("Schema file modified, recompiling...");
println!("🔄 Schema changed, recompiling...");
tokio::time::sleep(Duration::from_millis(100)).await;
match compile_schema(schema).await {
Ok(()) => {
info!("Recompilation successful");
println!(" ✓ Recompiled successfully\n");
},
Err(e) => {
error!("Recompilation failed: {e}");
println!(" ❌ Compilation failed: {e}\n");
},
}
}
},
Err(e) => {
error!("Watch error: {e}");
anyhow::bail!("File watch error: {e}");
},
}
}
}
async fn compile_schema(input: &str) -> Result<()> {
let output = input.replace(".json", ".compiled.json");
super::compile::run(input, None, None, Vec::new(), Vec::new(), Vec::new(), &output, false, None)
.await
}