feat: Agregar campo id (UUID v4) a MonitoredApp
Cada app registrada ahora tiene un identificador único UUID v4. Se agrega la dependencia uuid al proyecto y se asegura que todas las rutas de creación de MonitoredApp generen un id único. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
13
Cargo.lock
generated
13
Cargo.lock
generated
@@ -1350,6 +1350,7 @@ dependencies = [
|
|||||||
"tokio",
|
"tokio",
|
||||||
"tokio-stream",
|
"tokio-stream",
|
||||||
"tower-http",
|
"tower-http",
|
||||||
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1711,6 +1712,18 @@ version = "1.0.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uuid"
|
||||||
|
version = "1.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.3.4",
|
||||||
|
"js-sys",
|
||||||
|
"serde_core",
|
||||||
|
"wasm-bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vcpkg"
|
name = "vcpkg"
|
||||||
version = "0.2.15"
|
version = "0.2.15"
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ serde = { version = "1.0", features = ["derive"] }
|
|||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
sysinfo = "0.30"
|
sysinfo = "0.30"
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
|
uuid = { version = "1.0", features = ["v4", "serde"] }
|
||||||
tower-http = { version = "0.5", features = ["cors"] }
|
tower-http = { version = "0.5", features = ["cors"] }
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
tokio-stream = "0.1"
|
tokio-stream = "0.1"
|
||||||
|
|||||||
@@ -2,10 +2,15 @@ use serde::{Serialize, Deserialize};
|
|||||||
use std::fs::{self, create_dir_all};
|
use std::fs::{self, create_dir_all};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::sync::{Arc, RwLock, OnceLock};
|
use std::sync::{Arc, RwLock, OnceLock};
|
||||||
|
use uuid::Uuid;
|
||||||
use crate::logger::get_logger;
|
use crate::logger::get_logger;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct MonitoredApp {
|
pub struct MonitoredApp {
|
||||||
|
/// ID único de la aplicación (UUID v4)
|
||||||
|
#[serde(default = "generate_uuid")]
|
||||||
|
pub id: String,
|
||||||
|
|
||||||
/// Nombre de la aplicación
|
/// Nombre de la aplicación
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
|
||||||
@@ -70,6 +75,10 @@ pub struct MonitoredApp {
|
|||||||
pub created_at: Option<String>,
|
pub created_at: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn generate_uuid() -> String {
|
||||||
|
Uuid::new_v4().to_string()
|
||||||
|
}
|
||||||
|
|
||||||
fn default_mode() -> String {
|
fn default_mode() -> String {
|
||||||
"production".to_string()
|
"production".to_string()
|
||||||
}
|
}
|
||||||
@@ -186,14 +195,20 @@ impl ConfigManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Agrega una app con información completa
|
/// Agrega una app con información completa
|
||||||
pub fn add_app_full(&self, app: MonitoredApp) -> Result<(), String> {
|
pub fn add_app_full(&self, mut app: MonitoredApp) -> Result<(), String> {
|
||||||
let mut config = self.config.write().unwrap();
|
let mut config = self.config.write().unwrap();
|
||||||
|
|
||||||
// Verificar si ya existe
|
// Verificar si ya existe una app ACTIVA con el mismo nombre
|
||||||
if config.apps.iter().any(|a| a.name == app.name) {
|
// (las apps eliminadas no cuentan, pueden tener el mismo nombre)
|
||||||
|
if config.apps.iter().any(|a| a.name == app.name && !a.deleted) {
|
||||||
return Err(format!("La app '{}' ya está siendo monitoreada", app.name));
|
return Err(format!("La app '{}' ya está siendo monitoreada", app.name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Asegurar que tenga un UUID único
|
||||||
|
if app.id.is_empty() {
|
||||||
|
app.id = Uuid::new_v4().to_string();
|
||||||
|
}
|
||||||
|
|
||||||
config.apps.push(app);
|
config.apps.push(app);
|
||||||
|
|
||||||
// Guardar en disco
|
// Guardar en disco
|
||||||
@@ -210,6 +225,7 @@ impl ConfigManager {
|
|||||||
let registered_at = chrono::Local::now().to_rfc3339();
|
let registered_at = chrono::Local::now().to_rfc3339();
|
||||||
|
|
||||||
let app = MonitoredApp {
|
let app = MonitoredApp {
|
||||||
|
id: Uuid::new_v4().to_string(),
|
||||||
name,
|
name,
|
||||||
service_name,
|
service_name,
|
||||||
path: String::new(),
|
path: String::new(),
|
||||||
@@ -231,6 +247,45 @@ impl ConfigManager {
|
|||||||
self.add_app_full(app)
|
self.add_app_full(app)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Actualiza una app existente (sin crear duplicados)
|
||||||
|
pub fn update_app(&self, name: &str, updated_app: MonitoredApp) -> Result<(), String> {
|
||||||
|
let mut config = self.config.write().unwrap();
|
||||||
|
|
||||||
|
// Buscar la app activa con ese nombre
|
||||||
|
let app = config.apps.iter_mut().find(|a| a.name == name && !a.deleted);
|
||||||
|
|
||||||
|
match app {
|
||||||
|
Some(app) => {
|
||||||
|
// Preservar el ID original y la fecha de registro
|
||||||
|
let original_id = app.id.clone();
|
||||||
|
let original_registered_at = app.registered_at.clone();
|
||||||
|
|
||||||
|
// Actualizar todos los campos
|
||||||
|
app.name = updated_app.name;
|
||||||
|
app.service_name = updated_app.service_name;
|
||||||
|
app.path = updated_app.path;
|
||||||
|
app.port = updated_app.port;
|
||||||
|
app.entry_point = updated_app.entry_point;
|
||||||
|
app.node_bin = updated_app.node_bin;
|
||||||
|
app.mode = updated_app.mode;
|
||||||
|
app.user = updated_app.user;
|
||||||
|
app.service_file_path = updated_app.service_file_path;
|
||||||
|
app.environment = updated_app.environment;
|
||||||
|
|
||||||
|
// Mantener el ID original y fecha de registro
|
||||||
|
app.id = original_id;
|
||||||
|
app.registered_at = original_registered_at;
|
||||||
|
|
||||||
|
// Guardar en disco
|
||||||
|
match Self::save_config_to_file(&self.config_path, &config) {
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(e) => Err(format!("Error al guardar configuración: {}", e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => Err(format!("La app '{}' no se encontró", name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Realiza un soft delete: marca la app como eliminada pero mantiene el registro
|
/// Realiza un soft delete: marca la app como eliminada pero mantiene el registro
|
||||||
pub fn soft_delete_app(&self, name: &str, reason: Option<String>) -> Result<(), String> {
|
pub fn soft_delete_app(&self, name: &str, reason: Option<String>) -> Result<(), String> {
|
||||||
let mut config = self.config.write().unwrap();
|
let mut config = self.config.write().unwrap();
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/// Módulo para descubrir servicios systemd existentes
|
/// Módulo para descubrir servicios systemd existentes
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use uuid::Uuid;
|
||||||
use crate::logger::get_logger;
|
use crate::logger::get_logger;
|
||||||
use crate::config::{get_config_manager, MonitoredApp};
|
use crate::config::{get_config_manager, MonitoredApp};
|
||||||
|
|
||||||
@@ -232,7 +233,8 @@ pub fn sync_discovered_services(services: Vec<DiscoveredService>) {
|
|||||||
detect_port_from_name(&service.app_name)
|
detect_port_from_name(&service.app_name)
|
||||||
});
|
});
|
||||||
|
|
||||||
// Verificar si ya existe en la configuración
|
// Verificar si ya existe una app ACTIVA en la configuración
|
||||||
|
// (get_apps() ya filtra las eliminadas, así que esto está bien)
|
||||||
let existing_apps = config_manager.get_apps();
|
let existing_apps = config_manager.get_apps();
|
||||||
let already_exists = existing_apps.iter().any(|app| app.name == service.app_name);
|
let already_exists = existing_apps.iter().any(|app| app.name == service.app_name);
|
||||||
|
|
||||||
@@ -248,6 +250,7 @@ pub fn sync_discovered_services(services: Vec<DiscoveredService>) {
|
|||||||
let registered_at = chrono::Local::now().to_rfc3339();
|
let registered_at = chrono::Local::now().to_rfc3339();
|
||||||
|
|
||||||
let app = MonitoredApp {
|
let app = MonitoredApp {
|
||||||
|
id: Uuid::new_v4().to_string(),
|
||||||
name: service.app_name.clone(),
|
name: service.app_name.clone(),
|
||||||
service_name,
|
service_name,
|
||||||
path: service.working_directory.unwrap_or_default(),
|
path: service.working_directory.unwrap_or_default(),
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ use crate::logger::get_logger;
|
|||||||
use crate::config::{get_config_manager, MonitoredApp};
|
use crate::config::{get_config_manager, MonitoredApp};
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
pub struct AppManager {
|
pub struct AppManager {
|
||||||
apps: Arc<DashMap<String, ServiceConfig>>,
|
apps: Arc<DashMap<String, ServiceConfig>>,
|
||||||
@@ -79,6 +80,7 @@ impl AppManager {
|
|||||||
.unwrap_or_else(|| "production".to_string());
|
.unwrap_or_else(|| "production".to_string());
|
||||||
|
|
||||||
let monitored_app = MonitoredApp {
|
let monitored_app = MonitoredApp {
|
||||||
|
id: Uuid::new_v4().to_string(),
|
||||||
name: config.app_name.clone(),
|
name: config.app_name.clone(),
|
||||||
service_name: config.service_name(),
|
service_name: config.service_name(),
|
||||||
path: config.working_directory.clone(),
|
path: config.working_directory.clone(),
|
||||||
|
|||||||
Reference in New Issue
Block a user