use crate::agent::AgentCoordinator;
use crate::api::{GrpcTypeService, WebSocketServer};
use crate::core::SharedUniverse;
use std::net::SocketAddr;
use std::sync::Arc;
use tracing::{error, info};
#[derive(Debug, Clone)]
pub struct DaemonConfig {
pub grpc_addr: SocketAddr,
pub ws_addr: SocketAddr,
pub ipc_socket: std::path::PathBuf,
pub preload_stdlib: bool,
pub enable_grpc: bool,
pub enable_ws: bool,
pub enable_ipc: bool,
}
impl Default for DaemonConfig {
fn default() -> Self {
#[cfg(unix)]
let ipc_socket = dirs::runtime_dir()
.unwrap_or_else(std::env::temp_dir)
.join("wootype.sock");
#[cfg(windows)]
let ipc_socket = std::env::temp_dir().join("wootype.sock");
Self {
grpc_addr: "[::1]:50051".parse().unwrap(),
ws_addr: "[::1]:8080".parse().unwrap(),
ipc_socket,
preload_stdlib: false,
enable_grpc: true,
enable_ws: true,
enable_ipc: true,
}
}
}
pub struct TypeDaemon {
config: DaemonConfig,
universe: SharedUniverse,
coordinator: Arc<AgentCoordinator>,
}
impl TypeDaemon {
pub fn new(config: DaemonConfig) -> Self {
let universe = Arc::new(crate::core::TypeUniverse::new());
let coordinator = Arc::new(AgentCoordinator::new(universe.clone()));
info!("🚀 Type Daemon initialized");
info!(" Universe size: {} types", universe.type_count());
Self {
config,
universe,
coordinator,
}
}
pub async fn run(&self) -> Result<(), DaemonError> {
info!("Starting Type Daemon...");
if self.config.preload_stdlib {
self.preload_stdlib().await?;
}
let mut handles = vec![];
if self.config.enable_grpc {
let grpc_handle = self.start_grpc().await?;
handles.push(grpc_handle);
}
if self.config.enable_ws {
let ws_handle = self.start_websocket().await?;
handles.push(ws_handle);
}
for handle in handles {
if let Err(e) = handle.await {
error!("Service error: {}", e);
}
}
Ok(())
}
async fn preload_stdlib(&self) -> Result<(), DaemonError> {
info!("Preloading stdlib packages...");
let importer = crate::parser::PackageImporter::new(self.universe.clone());
let results = importer.preload_stdlib().await;
let total_imported: usize = results.iter().map(|r| r.types_imported).sum();
info!("Preloaded {} types from stdlib", total_imported);
Ok(())
}
async fn start_grpc(&self) -> Result<tokio::task::JoinHandle<()>, DaemonError> {
info!("Starting gRPC server on {}", self.config.grpc_addr);
let service = GrpcTypeService::new(self.universe.clone(), self.coordinator.clone());
let addr = self.config.grpc_addr;
let reflection_service = tonic_reflection::server::Builder::configure()
.register_encoded_file_descriptor_set(crate::api::grpc::proto::FILE_DESCRIPTOR_SET)
.build_v1()
.map_err(|e| DaemonError::Internal(e.to_string()))?;
let handle = tokio::spawn(async move {
tonic::transport::Server::builder()
.add_service(service.into_service())
.add_service(reflection_service)
.serve(addr)
.await
.expect("gRPC server failed");
});
Ok(handle)
}
async fn start_websocket(&self) -> Result<tokio::task::JoinHandle<()>, DaemonError> {
info!("Starting WebSocket server on {}", self.config.ws_addr);
let server = WebSocketServer::new(
self.config.ws_addr,
self.universe.clone(),
self.coordinator.clone(),
);
let handle = tokio::spawn(async move {
if let Err(e) = server.start().await {
error!("WebSocket server error: {}", e);
}
});
Ok(handle)
}
pub fn stats(&self) -> DaemonStats {
DaemonStats {
universe_size: self.universe.type_count(),
active_sessions: 0, uptime_secs: 0,
}
}
}
#[derive(Debug)]
pub struct DaemonStats {
pub universe_size: usize,
pub active_sessions: usize,
pub uptime_secs: u64,
}
#[derive(Debug)]
pub enum DaemonError {
Io(std::io::Error),
Transport(tonic::transport::Error),
Internal(String),
}
impl std::fmt::Display for DaemonError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Io(e) => write!(f, "IO error: {}", e),
Self::Transport(e) => write!(f, "Transport error: {}", e),
Self::Internal(s) => write!(f, "Internal error: {}", s),
}
}
}
impl std::error::Error for DaemonError {}
impl From<std::io::Error> for DaemonError {
fn from(e: std::io::Error) -> Self {
Self::Io(e)
}
}
impl From<tonic::transport::Error> for DaemonError {
fn from(e: tonic::transport::Error) -> Self {
Self::Transport(e)
}
}