feat: Mejorar estructura de monitored_apps.json con metadata completa

- Añadir campos al modelo MonitoredApp:
  * service_name: Nombre del servicio systemd
  * path: WorkingDirectory de la aplicación
  * entry_point: Archivo de entrada (server.js, app.js, etc.)
  * node_bin: Ruta completa al binario de node/python
  * mode: Modo de ejecución (production, development, test)
  * service_file_path: Ruta al archivo .service de systemd
  * registered_at: Timestamp de registro (ISO 8601)

- Actualizar discovery.rs para extraer toda la información:
  * Parsear ExecStart para obtener node_bin y entry_point
  * Extraer NODE_ENV para determinar el modo
  * Guardar ruta completa al archivo .service
  * Usar add_app_full() con información completa

- Integrar ConfigManager en AppManager:
  * Guardar automáticamente en monitored_apps.json al registrar apps
  * Eliminar del JSON al desregistrar apps
  * Extraer metadata desde ServiceConfig (puerto, entry_point, mode, etc.)

- Mantener retrocompatibilidad con JSON antiguo mediante campos deprecated
- Todos los nuevos campos usan #[serde(default)] para evitar errores de deserialización
This commit is contained in:
2026-01-18 03:26:42 -05:00
parent ad9b46bdc5
commit 8822e9e6b5
21 changed files with 3246 additions and 642 deletions

View File

@@ -6,14 +6,51 @@ use crate::logger::get_logger;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MonitoredApp {
/// Nombre de la aplicación
pub name: String,
/// Nombre del servicio systemd (ej: siax-app-TAREAS.service)
#[serde(default)]
pub service_name: String,
/// Ruta completa al directorio de la aplicación (WorkingDirectory)
#[serde(default)]
pub path: String,
/// Puerto donde escucha la aplicación
pub port: i32,
/// Archivo de entrada (ej: server.js, app.js)
#[serde(default)]
pub entry_point: String,
/// Ruta completa al binario de node/python
#[serde(default)]
pub node_bin: String,
/// Modo de ejecución (production, development, test)
#[serde(default = "default_mode")]
pub mode: String,
/// Ruta completa al archivo .service de systemd
#[serde(default)]
pub service_file_path: String,
/// Fecha de registro (ISO 8601)
#[serde(default, skip_serializing_if = "String::is_empty", rename = "reg")]
pub registered_at: String,
// DEPRECATED: Mantener por compatibilidad con versiones antiguas
#[serde(skip_serializing_if = "Option::is_none")]
pub systemd_service: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub created_at: Option<String>,
}
fn default_mode() -> String {
"production".to_string()
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AppConfig {
pub apps: Vec<MonitoredApp>,
@@ -99,23 +136,16 @@ impl ConfigManager {
config.apps.clone()
}
pub fn add_app(&self, name: String, port: i32) -> Result<(), String> {
/// Agrega una app con información completa
pub fn add_app_full(&self, app: MonitoredApp) -> Result<(), String> {
let mut config = self.config.write().unwrap();
// Verificar si ya existe
if config.apps.iter().any(|app| app.name == name) {
return Err(format!("La app '{}' ya está siendo monitoreada", name));
if config.apps.iter().any(|a| a.name == app.name) {
return Err(format!("La app '{}' ya está siendo monitoreada", app.name));
}
let systemd_service = format!("siax-app-{}.service", name);
let created_at = chrono::Local::now().to_rfc3339();
config.apps.push(MonitoredApp {
name,
port,
systemd_service: Some(systemd_service),
created_at: Some(created_at),
});
config.apps.push(app);
// Guardar en disco
match Self::save_config_to_file(&self.config_path, &config) {
@@ -124,6 +154,29 @@ impl ConfigManager {
}
}
/// Método simplificado para compatibilidad (DEPRECATED)
#[deprecated(note = "Usar add_app_full() con MonitoredApp completo")]
pub fn add_app(&self, name: String, port: i32) -> Result<(), String> {
let service_name = format!("siax-app-{}.service", name);
let registered_at = chrono::Local::now().to_rfc3339();
let app = MonitoredApp {
name,
service_name,
path: String::new(),
port,
entry_point: String::new(),
node_bin: String::new(),
mode: "production".to_string(),
service_file_path: String::new(),
registered_at,
systemd_service: None,
created_at: None,
};
self.add_app_full(app)
}
pub fn remove_app(&self, name: &str) -> Result<(), String> {
let mut config = self.config.write().unwrap();