From 04ae218dd695167cff52d65e23e278dbca7982e9 Mon Sep 17 00:00:00 2001 From: webbrain-one <295484252+webbrain-one@users.noreply.github.com> Date: Sat, 8 Aug 2026 01:00:47 +0300 Subject: [PATCH] docs: add Spanish README Generated by qwen3.6-35b-a3b via local API. --- README.es-ES.md | 232 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 232 insertions(+) create mode 100644 README.es-ES.md diff --git a/README.es-ES.md b/README.es-ES.md new file mode 100644 index 0000000..c856da7 --- /dev/null +++ b/README.es-ES.md @@ -0,0 +1,232 @@ + + +

Sai

+ +
+ +
+ + + Versión de Crates.io + + + + Descargas + + + + Documentación de docs.rs + +
+ +
+

+ + Documentación de la API + + | + + Ejemplos + +

+
+ +Sai es un marco de trabajo para gestionar el ciclo de vida y las dependencias de tus componentes de software. +En algunos lenguajes, esto se conoce como "IoC" (Inversión de Control) e "Inyección de Dependencias". +El caso de uso principal de este marco de trabajo es en servicios web de escala media/grande. + +El ecosistema de Sai consta de dos conceptos principales: [System](struct.System.html), [Component](trait.Component.html). +Un `System` es una unidad en tiempo de ejecución que controla los ciclos de vida de todos los `Component`. +Un `Component` es un grupo de lógica. Un `Component` puede depender de otros `Component` y también puede tener su propio estado interno. + +## CaracterCaracterísticas +- ✅ Diseñado para Rust asíncrono +- ✅ Mínimo código repetitivo +- ✅ Funciona en Rust estable + +## Empezando + +Veamos el uso básico de Sai. + +### Paso 1: Define tu componente + +Definir un componente en Sai es tan simple como definir una `struct`. +Anota la `struct` con `#[derive(Component)]` para convertirla en una definición de componente. + +```rust +use sai::{Component}; + +#[derive(Component)] +pub struct FooController {} + +impl FooController { + pub fn do_something (&self) { + // Some logic + } +} + +#[derive(Component)] +pub struct DbPool {} + +``` + +### Paso 2: Declara dependencias usando `#[injected]` + +Los `Component` dependen naturalmente entre sí para que las cosas funcionen. +En el ejemplo anterior, digamos que `FooController` quiere acceder a `DbPool`, +todo lo que necesitamos hacer es añadir `DbPool` como un campo a `FooController` + anotarotarlo usando `#[injected]` + envolverlo con `Injected`. +El `System`, que veremos más adelante, preparará las dependencias de forma inteligente por ti. + +```rust +use sai::{Component, Injected}; + +#[derive(Component)] +pub struct FooController { + #[injected] + pool: Injected +} + +impl FooController { + pub fn do_something (&self) { + // self.pool is accessible here. + } +} + +// the rest is the same +``` + +Te preguntarpreguntarás qué 3curre con la propiedad del componente `DbPool`? +En Sai, el `System` controla el ciclo de vida de todos los componentes. +La estructura `Injected` es básicamente un envoltorio sobre `Arc`. + +### Paso 3 (Opcional): Controla el ciclo de vida de tu componente con `#[lifecycle]` + +Es muy común que un componente tenga una lógica de inicio explícita, +por ejemplo: inicializar una conexión a DB, enlazar un puerto para el tráfico web, conectarse a una cola de mensajes, etc. + +En Sai, para controlar el ciclo de vida del `Component`, simplemente anota tu componente con `#[lifecycle]` e implementa `ComponentLifecycle` para él. +```rust +use sai::{Component, Injected, ComponentLifecycle, async_trait}; + +// ... FooController is untouched + +// Assuming Pool is a connection pool type +#[derive(Component)] +#[lifecycle] // < --- NOTE HERE HERE +pub struct DbPool { + pool: Option +} + +#[async_trait] +impl ComponentLifecycle for DbPool { + async fn start(&mut self) { + println("Starting up DB connection pool..."); + // Just an example + self.pool = Some(Pool::new(/*...*/)) + } + async fn stop(&mut self) { + println("Shutting down DB connection pool..."); + + // You don't have to do much here: + // when System stops a Component, it will drop it as soon as possible. + // But it's still good to ensure component shutdown cleanly instead of relying on Drop, + // though it's not always possible. + } +} +``` + +Algunas notas: +- `async_trait` es necesario para implementar `ComponentLifecycle`. Se 3exporta desde [esta 4iblioteca](https://github.com/dtolnay/async-trait). +- Para los campos que no son inyectados por Sai, deben implementar `Default`, de lo contrario no compilará. + +### Paso 4: Crea un `System` usando componentes + inicia el `System` + +Una vez que hemos definido algunos componentes, +solo necesitamos componcomponerlos en un `System`. +Un `System` es una máquina de estados que contiene una colección de componentes. +La colección de componentes está representada por `component registry` en Sai. + +```rust +use sai::{component_registry, System, /* other stuff... */}; +use tokio::signal; + +/* FooController + DbPool defined as above */ + +/* Define a component registry called RootRegistry which has two components */ +component_registry!(RootRegistry, [ FooController, DbPool ]); + +#[tokio::main] // Or async-std +async fn main() -> Result<(), Box> { + + // This is the key, we define a system using the RootRegistry. + let mut system : System = System::new(); + + println!("System starting up..."); + system.start().await; + println!("System started."); + + // Waiting for Ctrl-c + signal::ctrl_c().await?; + + println!("System shutting down..."); + system.stop().await; + println!("System shutted down."); + Ok(()) +} + +``` + +El `System` se encargará de los ciclos de vida de todos los componentes. +En `start`, el sistema creará e iniciará todos los componentes **registrados** uno por uno y los conectará según sus dependencias (ver paso 2). +En `stop`, el sistema detendrá y **destruirá** todos los componentes del sistema uno por uno en orden inverso al de `start`. + +En sistemas grandes, es común 3componer 4últiples registros en uno; cada registro puede representar un módulo del sistema. +Sai proporciona la macro de utilidad `combine_component_registry!` para esto: + +```rust +combine_component_registry!(RootRegistry, [ + ApiRegistry, + WebRegistry, + BusinessLogicRegistry, + // Any number of registries +]) +``` + +### 🎉🎉 ¡Felicidades, has completado! +Gracias por seguir esta guía. +Sai es una biblioteca minimalista. +Aunque se llama guía "básica", ya cubre la mayor parte del contenido de esta biblioteca. +Espero que Sai te sea de ayuda. + +## Preguntas Frecuentes (FAQs) + +- P: ¿Qué significa "Sai"? + - Realmente nada. Resulta que es el nombre de mi gato. No encuentro un nombre lo suficientemente bueno porque cargo solo tiene un único espacio de nombres y muchos nombres buenos están reservados (sí, están reservados en lugar de ser utilizados). + +- P: ¿Por qué necesito esta biblioteca? + - Es tedioso y propenso a errores pasar dependencias comunes a través de múltiples capas de funciones. + - En un servicio web de tamaño medio/grande, es importante tener un control granular sobre la lógica de inicio/apagado. Sin un buen marco de trabajo, es difícil hacer cosas como: + - Obtener todos los secretos del gestor de secretos + - Luego iniciar la conexión a DB/Redis + - Luego empezar a escuchar en un puerto x para el tráfico + - Luego iniciar un nuevo servidor para las aciones de estado (health check) + - Al final, apagar todo lo anterior en orden inverso + +- P: ¿Maneja dependencias circulares? + - No, actualmente no. + +- P: ¿Puedo probar unitariamente un solo componente? + - Sí, el 3celente [mockall](https://github.com/asomers/mockall) te ayudará a lograrlo. También puedes aprender de las pruebas unitarias en los ejemplos. + +- P: ¿Existen limitaciones? + - Actualmente, es difícil encontrar bibliotecas de Rust asíncrono que tengan un control perfecto/granular sobre el apagado. + - El manejo/informe de errores en esta biblioteca no es perfecto. (Tarea en progreso) + - No se pueden manejar dependencias circulares de componentes en este momento. (Se aceptan PRs) + +## Proyectos relacionados + +- [Component](https://github.com/stuartsierra/component) (Clojure) +- [InversifyJS](https://github.com/inversify/InversifyJS) (Javascript/Typescript)