pub struct ForgeDaemon<SetupOutput> { /* private fields */ }Expand description
Main constructor to configure and launch the daemon process.
SetupOutput represents the return type of the privileged setup action.
The daemonized process will return this value wrapped in a DaemonResult.
Implementations§
Source§impl ForgeDaemon<()>
impl ForgeDaemon<()>
Sourcepub fn new() -> Self
pub fn new() -> Self
Creates a new default configuration.
§Defaults
- Working directory:
/(Unix) orC:\(Windows) - Stdio:
/dev/null - Umask:
0o027(Unix)
Examples found in repository?
11fn main() -> Result<(), Box<dyn std::error::Error>> {
12 // 1. Definir rutas
13 let pwd = env::current_dir().unwrap();
14 let log_path = pwd.join("ticker.log");
15 let err_path = pwd.join("ticker.err");
16 let pid_path = pwd.join("ticker.pid");
17
18 // 2. Abrir archivos de log (Append mode)
19 let stdout_file = OpenOptions::new()
20 .create(true)
21 .append(true)
22 .open(&log_path)
23 .expect("Couldn't open stdout");
24
25 let stderr_file = OpenOptions::new()
26 .create(true)
27 .append(true)
28 .open(&err_path)
29 .expect("Couldn't open stderr");
30
31 println!("Launching a simple ticker Daemon...");
32 println!("Logs will be written to: {:?}", log_path);
33
34 // 3. Configurar el Daemon
35 let daemon = ForgeDaemon::new()
36 .name("tick_daemon")
37 .pid_file(&pid_path)
38 .working_directory(&pwd)
39 .stdout(stdout_file)
40 .stderr(stderr_file)
41 // AQUÍ está el cambio principal: Pasamos la lógica como un closure
42 .privileged_action(move || {
43
44 // --- INICIO CÓDIGO DEL DAEMON ---
45
46 // A. Configurar manejo de señales para parada limpia (SIGTERM / SIGINT)
47 let term = Arc::new(AtomicBool::new(false));
48 flag::register(SIGTERM, Arc::clone(&term))?; // Systemd Stop
49 flag::register(SIGINT, Arc::clone(&term))?; // Ctrl+C (Manual)
50
51 println!("[Ticker] Servicio iniciado. PID: {}", std::process::id());
52
53 let frases = [
54 "Estan vivos",
55 "I have no mouth",
56 "I must scream",
57 "Hello world",
58 "Adios mundo :0"
59 ];
60
61 let mut i = 0;
62
63 // B. Bucle principal que respeta la señal de parada
64 while !term.load(Ordering::Relaxed) {
65 let frase = frases[i % frases.len()];
66
67 // C. Usamos println!: La librería ya redirigió esto al archivo .log
68 println!("[Ticker] Ping #{} - {}", i, frase);
69
70 i += 1;
71
72 // Dormir en intervalos cortos para revisar la señal de parada frecuentemente
73 thread::sleep(Duration::from_secs(3));
74 }
75
76 println!("[Ticker] Señal de parada recibida. Cerrando limpiamente.");
77 Ok(())
78 });
79
80 // 4. Arrancar usando la lógica refactorizada (Systemd o Fork)
81 // Nota: Usamos la función del módulo unix directamente
82 daemon_forge::ForgeDaemon::start(daemon)?;
83
84 Ok(())
85}Source§impl<SetupOutput> ForgeDaemon<SetupOutput>
impl<SetupOutput> ForgeDaemon<SetupOutput>
Sourcepub fn pid_file_path(&self) -> Option<&Path>
pub fn pid_file_path(&self) -> Option<&Path>
Returns the configured PID file path, if any.
Sourcepub fn environment(&self) -> &HashMap<String, String>
pub fn environment(&self) -> &HashMap<String, String>
Returns a reference to the environment variables map.
Sourcepub fn working_directory_path(&self) -> &Path
pub fn working_directory_path(&self) -> &Path
Returns the configured working directory.
Sourcepub fn name(self, name: &str) -> Self
pub fn name(self, name: &str) -> Self
Sets the internal name of the daemon.
On Windows, this name is used to create a Global Mutex for single-instance locking.
Examples found in repository?
11fn main() -> Result<(), Box<dyn std::error::Error>> {
12 // 1. Definir rutas
13 let pwd = env::current_dir().unwrap();
14 let log_path = pwd.join("ticker.log");
15 let err_path = pwd.join("ticker.err");
16 let pid_path = pwd.join("ticker.pid");
17
18 // 2. Abrir archivos de log (Append mode)
19 let stdout_file = OpenOptions::new()
20 .create(true)
21 .append(true)
22 .open(&log_path)
23 .expect("Couldn't open stdout");
24
25 let stderr_file = OpenOptions::new()
26 .create(true)
27 .append(true)
28 .open(&err_path)
29 .expect("Couldn't open stderr");
30
31 println!("Launching a simple ticker Daemon...");
32 println!("Logs will be written to: {:?}", log_path);
33
34 // 3. Configurar el Daemon
35 let daemon = ForgeDaemon::new()
36 .name("tick_daemon")
37 .pid_file(&pid_path)
38 .working_directory(&pwd)
39 .stdout(stdout_file)
40 .stderr(stderr_file)
41 // AQUÍ está el cambio principal: Pasamos la lógica como un closure
42 .privileged_action(move || {
43
44 // --- INICIO CÓDIGO DEL DAEMON ---
45
46 // A. Configurar manejo de señales para parada limpia (SIGTERM / SIGINT)
47 let term = Arc::new(AtomicBool::new(false));
48 flag::register(SIGTERM, Arc::clone(&term))?; // Systemd Stop
49 flag::register(SIGINT, Arc::clone(&term))?; // Ctrl+C (Manual)
50
51 println!("[Ticker] Servicio iniciado. PID: {}", std::process::id());
52
53 let frases = [
54 "Estan vivos",
55 "I have no mouth",
56 "I must scream",
57 "Hello world",
58 "Adios mundo :0"
59 ];
60
61 let mut i = 0;
62
63 // B. Bucle principal que respeta la señal de parada
64 while !term.load(Ordering::Relaxed) {
65 let frase = frases[i % frases.len()];
66
67 // C. Usamos println!: La librería ya redirigió esto al archivo .log
68 println!("[Ticker] Ping #{} - {}", i, frase);
69
70 i += 1;
71
72 // Dormir en intervalos cortos para revisar la señal de parada frecuentemente
73 thread::sleep(Duration::from_secs(3));
74 }
75
76 println!("[Ticker] Señal de parada recibida. Cerrando limpiamente.");
77 Ok(())
78 });
79
80 // 4. Arrancar usando la lógica refactorizada (Systemd o Fork)
81 // Nota: Usamos la función del módulo unix directamente
82 daemon_forge::ForgeDaemon::start(daemon)?;
83
84 Ok(())
85}Sourcepub fn pid_file<P: Into<PathBuf>>(self, path: P) -> Self
pub fn pid_file<P: Into<PathBuf>>(self, path: P) -> Self
Sets the path to the PID file. This file is used for locking to ensure only one instance runs.
Examples found in repository?
11fn main() -> Result<(), Box<dyn std::error::Error>> {
12 // 1. Definir rutas
13 let pwd = env::current_dir().unwrap();
14 let log_path = pwd.join("ticker.log");
15 let err_path = pwd.join("ticker.err");
16 let pid_path = pwd.join("ticker.pid");
17
18 // 2. Abrir archivos de log (Append mode)
19 let stdout_file = OpenOptions::new()
20 .create(true)
21 .append(true)
22 .open(&log_path)
23 .expect("Couldn't open stdout");
24
25 let stderr_file = OpenOptions::new()
26 .create(true)
27 .append(true)
28 .open(&err_path)
29 .expect("Couldn't open stderr");
30
31 println!("Launching a simple ticker Daemon...");
32 println!("Logs will be written to: {:?}", log_path);
33
34 // 3. Configurar el Daemon
35 let daemon = ForgeDaemon::new()
36 .name("tick_daemon")
37 .pid_file(&pid_path)
38 .working_directory(&pwd)
39 .stdout(stdout_file)
40 .stderr(stderr_file)
41 // AQUÍ está el cambio principal: Pasamos la lógica como un closure
42 .privileged_action(move || {
43
44 // --- INICIO CÓDIGO DEL DAEMON ---
45
46 // A. Configurar manejo de señales para parada limpia (SIGTERM / SIGINT)
47 let term = Arc::new(AtomicBool::new(false));
48 flag::register(SIGTERM, Arc::clone(&term))?; // Systemd Stop
49 flag::register(SIGINT, Arc::clone(&term))?; // Ctrl+C (Manual)
50
51 println!("[Ticker] Servicio iniciado. PID: {}", std::process::id());
52
53 let frases = [
54 "Estan vivos",
55 "I have no mouth",
56 "I must scream",
57 "Hello world",
58 "Adios mundo :0"
59 ];
60
61 let mut i = 0;
62
63 // B. Bucle principal que respeta la señal de parada
64 while !term.load(Ordering::Relaxed) {
65 let frase = frases[i % frases.len()];
66
67 // C. Usamos println!: La librería ya redirigió esto al archivo .log
68 println!("[Ticker] Ping #{} - {}", i, frase);
69
70 i += 1;
71
72 // Dormir en intervalos cortos para revisar la señal de parada frecuentemente
73 thread::sleep(Duration::from_secs(3));
74 }
75
76 println!("[Ticker] Señal de parada recibida. Cerrando limpiamente.");
77 Ok(())
78 });
79
80 // 4. Arrancar usando la lógica refactorizada (Systemd o Fork)
81 // Nota: Usamos la función del módulo unix directamente
82 daemon_forge::ForgeDaemon::start(daemon)?;
83
84 Ok(())
85}Sourcepub fn working_directory<P: Into<PathBuf>>(self, path: P) -> Self
pub fn working_directory<P: Into<PathBuf>>(self, path: P) -> Self
Sets the working directory for the daemon.
Examples found in repository?
11fn main() -> Result<(), Box<dyn std::error::Error>> {
12 // 1. Definir rutas
13 let pwd = env::current_dir().unwrap();
14 let log_path = pwd.join("ticker.log");
15 let err_path = pwd.join("ticker.err");
16 let pid_path = pwd.join("ticker.pid");
17
18 // 2. Abrir archivos de log (Append mode)
19 let stdout_file = OpenOptions::new()
20 .create(true)
21 .append(true)
22 .open(&log_path)
23 .expect("Couldn't open stdout");
24
25 let stderr_file = OpenOptions::new()
26 .create(true)
27 .append(true)
28 .open(&err_path)
29 .expect("Couldn't open stderr");
30
31 println!("Launching a simple ticker Daemon...");
32 println!("Logs will be written to: {:?}", log_path);
33
34 // 3. Configurar el Daemon
35 let daemon = ForgeDaemon::new()
36 .name("tick_daemon")
37 .pid_file(&pid_path)
38 .working_directory(&pwd)
39 .stdout(stdout_file)
40 .stderr(stderr_file)
41 // AQUÍ está el cambio principal: Pasamos la lógica como un closure
42 .privileged_action(move || {
43
44 // --- INICIO CÓDIGO DEL DAEMON ---
45
46 // A. Configurar manejo de señales para parada limpia (SIGTERM / SIGINT)
47 let term = Arc::new(AtomicBool::new(false));
48 flag::register(SIGTERM, Arc::clone(&term))?; // Systemd Stop
49 flag::register(SIGINT, Arc::clone(&term))?; // Ctrl+C (Manual)
50
51 println!("[Ticker] Servicio iniciado. PID: {}", std::process::id());
52
53 let frases = [
54 "Estan vivos",
55 "I have no mouth",
56 "I must scream",
57 "Hello world",
58 "Adios mundo :0"
59 ];
60
61 let mut i = 0;
62
63 // B. Bucle principal que respeta la señal de parada
64 while !term.load(Ordering::Relaxed) {
65 let frase = frases[i % frases.len()];
66
67 // C. Usamos println!: La librería ya redirigió esto al archivo .log
68 println!("[Ticker] Ping #{} - {}", i, frase);
69
70 i += 1;
71
72 // Dormir en intervalos cortos para revisar la señal de parada frecuentemente
73 thread::sleep(Duration::from_secs(3));
74 }
75
76 println!("[Ticker] Señal de parada recibida. Cerrando limpiamente.");
77 Ok(())
78 });
79
80 // 4. Arrancar usando la lógica refactorizada (Systemd o Fork)
81 // Nota: Usamos la función del módulo unix directamente
82 daemon_forge::ForgeDaemon::start(daemon)?;
83
84 Ok(())
85}Sourcepub fn stdout<S: Into<Stdio>>(self, stdio: S) -> Self
pub fn stdout<S: Into<Stdio>>(self, stdio: S) -> Self
Configures the standard output stream.
Examples found in repository?
11fn main() -> Result<(), Box<dyn std::error::Error>> {
12 // 1. Definir rutas
13 let pwd = env::current_dir().unwrap();
14 let log_path = pwd.join("ticker.log");
15 let err_path = pwd.join("ticker.err");
16 let pid_path = pwd.join("ticker.pid");
17
18 // 2. Abrir archivos de log (Append mode)
19 let stdout_file = OpenOptions::new()
20 .create(true)
21 .append(true)
22 .open(&log_path)
23 .expect("Couldn't open stdout");
24
25 let stderr_file = OpenOptions::new()
26 .create(true)
27 .append(true)
28 .open(&err_path)
29 .expect("Couldn't open stderr");
30
31 println!("Launching a simple ticker Daemon...");
32 println!("Logs will be written to: {:?}", log_path);
33
34 // 3. Configurar el Daemon
35 let daemon = ForgeDaemon::new()
36 .name("tick_daemon")
37 .pid_file(&pid_path)
38 .working_directory(&pwd)
39 .stdout(stdout_file)
40 .stderr(stderr_file)
41 // AQUÍ está el cambio principal: Pasamos la lógica como un closure
42 .privileged_action(move || {
43
44 // --- INICIO CÓDIGO DEL DAEMON ---
45
46 // A. Configurar manejo de señales para parada limpia (SIGTERM / SIGINT)
47 let term = Arc::new(AtomicBool::new(false));
48 flag::register(SIGTERM, Arc::clone(&term))?; // Systemd Stop
49 flag::register(SIGINT, Arc::clone(&term))?; // Ctrl+C (Manual)
50
51 println!("[Ticker] Servicio iniciado. PID: {}", std::process::id());
52
53 let frases = [
54 "Estan vivos",
55 "I have no mouth",
56 "I must scream",
57 "Hello world",
58 "Adios mundo :0"
59 ];
60
61 let mut i = 0;
62
63 // B. Bucle principal que respeta la señal de parada
64 while !term.load(Ordering::Relaxed) {
65 let frase = frases[i % frases.len()];
66
67 // C. Usamos println!: La librería ya redirigió esto al archivo .log
68 println!("[Ticker] Ping #{} - {}", i, frase);
69
70 i += 1;
71
72 // Dormir en intervalos cortos para revisar la señal de parada frecuentemente
73 thread::sleep(Duration::from_secs(3));
74 }
75
76 println!("[Ticker] Señal de parada recibida. Cerrando limpiamente.");
77 Ok(())
78 });
79
80 // 4. Arrancar usando la lógica refactorizada (Systemd o Fork)
81 // Nota: Usamos la función del módulo unix directamente
82 daemon_forge::ForgeDaemon::start(daemon)?;
83
84 Ok(())
85}Sourcepub fn stderr<S: Into<Stdio>>(self, stdio: S) -> Self
pub fn stderr<S: Into<Stdio>>(self, stdio: S) -> Self
Configures the standard error stream.
Examples found in repository?
11fn main() -> Result<(), Box<dyn std::error::Error>> {
12 // 1. Definir rutas
13 let pwd = env::current_dir().unwrap();
14 let log_path = pwd.join("ticker.log");
15 let err_path = pwd.join("ticker.err");
16 let pid_path = pwd.join("ticker.pid");
17
18 // 2. Abrir archivos de log (Append mode)
19 let stdout_file = OpenOptions::new()
20 .create(true)
21 .append(true)
22 .open(&log_path)
23 .expect("Couldn't open stdout");
24
25 let stderr_file = OpenOptions::new()
26 .create(true)
27 .append(true)
28 .open(&err_path)
29 .expect("Couldn't open stderr");
30
31 println!("Launching a simple ticker Daemon...");
32 println!("Logs will be written to: {:?}", log_path);
33
34 // 3. Configurar el Daemon
35 let daemon = ForgeDaemon::new()
36 .name("tick_daemon")
37 .pid_file(&pid_path)
38 .working_directory(&pwd)
39 .stdout(stdout_file)
40 .stderr(stderr_file)
41 // AQUÍ está el cambio principal: Pasamos la lógica como un closure
42 .privileged_action(move || {
43
44 // --- INICIO CÓDIGO DEL DAEMON ---
45
46 // A. Configurar manejo de señales para parada limpia (SIGTERM / SIGINT)
47 let term = Arc::new(AtomicBool::new(false));
48 flag::register(SIGTERM, Arc::clone(&term))?; // Systemd Stop
49 flag::register(SIGINT, Arc::clone(&term))?; // Ctrl+C (Manual)
50
51 println!("[Ticker] Servicio iniciado. PID: {}", std::process::id());
52
53 let frases = [
54 "Estan vivos",
55 "I have no mouth",
56 "I must scream",
57 "Hello world",
58 "Adios mundo :0"
59 ];
60
61 let mut i = 0;
62
63 // B. Bucle principal que respeta la señal de parada
64 while !term.load(Ordering::Relaxed) {
65 let frase = frases[i % frases.len()];
66
67 // C. Usamos println!: La librería ya redirigió esto al archivo .log
68 println!("[Ticker] Ping #{} - {}", i, frase);
69
70 i += 1;
71
72 // Dormir en intervalos cortos para revisar la señal de parada frecuentemente
73 thread::sleep(Duration::from_secs(3));
74 }
75
76 println!("[Ticker] Señal de parada recibida. Cerrando limpiamente.");
77 Ok(())
78 });
79
80 // 4. Arrancar usando la lógica refactorizada (Systemd o Fork)
81 // Nota: Usamos la función del módulo unix directamente
82 daemon_forge::ForgeDaemon::start(daemon)?;
83
84 Ok(())
85}Sourcepub fn clear_env(self, clear: bool) -> Self
pub fn clear_env(self, clear: bool) -> Self
If true, clears all inherited environment variables for security.
Sourcepub fn env_opt(self, key: &str, value: Option<&str>) -> Self
pub fn env_opt(self, key: &str, value: Option<&str>) -> Self
Adds an environment variable only if value is Some.
Sourcepub fn inherit_env(self) -> Self
pub fn inherit_env(self) -> Self
Inherits current environment variables into the configuration.
Useful when combined with clear_env(true) to selectively keep variables,
or to ensure specific variables are captured before cleaning.
Sourcepub fn build(self) -> DaemonResult<Self>
pub fn build(self) -> DaemonResult<Self>
Validates configuration without starting the daemon. Checks if the PID file directory exists.
Sourcepub fn privileged_action<N, F>(self, action: F) -> ForgeDaemon<N>where
F: FnOnce() -> DaemonResult<N> + 'static,
pub fn privileged_action<N, F>(self, action: F) -> ForgeDaemon<N>where
F: FnOnce() -> DaemonResult<N> + 'static,
Executes an action before dropping privileges (Unix) or before entering the main loop.
The action MUST return a DaemonResult. If it returns Err, the daemon will abort startup.
This consumes the current builder and returns a new one with the updated generic type N.
Examples found in repository?
11fn main() -> Result<(), Box<dyn std::error::Error>> {
12 // 1. Definir rutas
13 let pwd = env::current_dir().unwrap();
14 let log_path = pwd.join("ticker.log");
15 let err_path = pwd.join("ticker.err");
16 let pid_path = pwd.join("ticker.pid");
17
18 // 2. Abrir archivos de log (Append mode)
19 let stdout_file = OpenOptions::new()
20 .create(true)
21 .append(true)
22 .open(&log_path)
23 .expect("Couldn't open stdout");
24
25 let stderr_file = OpenOptions::new()
26 .create(true)
27 .append(true)
28 .open(&err_path)
29 .expect("Couldn't open stderr");
30
31 println!("Launching a simple ticker Daemon...");
32 println!("Logs will be written to: {:?}", log_path);
33
34 // 3. Configurar el Daemon
35 let daemon = ForgeDaemon::new()
36 .name("tick_daemon")
37 .pid_file(&pid_path)
38 .working_directory(&pwd)
39 .stdout(stdout_file)
40 .stderr(stderr_file)
41 // AQUÍ está el cambio principal: Pasamos la lógica como un closure
42 .privileged_action(move || {
43
44 // --- INICIO CÓDIGO DEL DAEMON ---
45
46 // A. Configurar manejo de señales para parada limpia (SIGTERM / SIGINT)
47 let term = Arc::new(AtomicBool::new(false));
48 flag::register(SIGTERM, Arc::clone(&term))?; // Systemd Stop
49 flag::register(SIGINT, Arc::clone(&term))?; // Ctrl+C (Manual)
50
51 println!("[Ticker] Servicio iniciado. PID: {}", std::process::id());
52
53 let frases = [
54 "Estan vivos",
55 "I have no mouth",
56 "I must scream",
57 "Hello world",
58 "Adios mundo :0"
59 ];
60
61 let mut i = 0;
62
63 // B. Bucle principal que respeta la señal de parada
64 while !term.load(Ordering::Relaxed) {
65 let frase = frases[i % frases.len()];
66
67 // C. Usamos println!: La librería ya redirigió esto al archivo .log
68 println!("[Ticker] Ping #{} - {}", i, frase);
69
70 i += 1;
71
72 // Dormir en intervalos cortos para revisar la señal de parada frecuentemente
73 thread::sleep(Duration::from_secs(3));
74 }
75
76 println!("[Ticker] Señal de parada recibida. Cerrando limpiamente.");
77 Ok(())
78 });
79
80 // 4. Arrancar usando la lógica refactorizada (Systemd o Fork)
81 // Nota: Usamos la función del módulo unix directamente
82 daemon_forge::ForgeDaemon::start(daemon)?;
83
84 Ok(())
85}Sourcepub fn user<U: Into<User>>(self, user: U) -> Self
pub fn user<U: Into<User>>(self, user: U) -> Self
(Unix) Sets the user to run the daemon as (privilege dropping).
Sourcepub fn group<G: Into<Group>>(self, group: G) -> Self
pub fn group<G: Into<Group>>(self, group: G) -> Self
(Unix) Sets the group to run the daemon as.
Sourcepub fn chroot<P: Into<PathBuf>>(self, path: P) -> Self
pub fn chroot<P: Into<PathBuf>>(self, path: P) -> Self
(Unix) Sets a chroot directory for the daemon.
Sourcepub fn chown_pid_file(self, chown: bool) -> Self
pub fn chown_pid_file(self, chown: bool) -> Self
(Unix) If true, changes ownership of the PID file to the target user/group.
Sourcepub fn start(self) -> DaemonResult<SetupOutput>
pub fn start(self) -> DaemonResult<SetupOutput>
Starts the daemonization process.
Examples found in repository?
11fn main() -> Result<(), Box<dyn std::error::Error>> {
12 // 1. Definir rutas
13 let pwd = env::current_dir().unwrap();
14 let log_path = pwd.join("ticker.log");
15 let err_path = pwd.join("ticker.err");
16 let pid_path = pwd.join("ticker.pid");
17
18 // 2. Abrir archivos de log (Append mode)
19 let stdout_file = OpenOptions::new()
20 .create(true)
21 .append(true)
22 .open(&log_path)
23 .expect("Couldn't open stdout");
24
25 let stderr_file = OpenOptions::new()
26 .create(true)
27 .append(true)
28 .open(&err_path)
29 .expect("Couldn't open stderr");
30
31 println!("Launching a simple ticker Daemon...");
32 println!("Logs will be written to: {:?}", log_path);
33
34 // 3. Configurar el Daemon
35 let daemon = ForgeDaemon::new()
36 .name("tick_daemon")
37 .pid_file(&pid_path)
38 .working_directory(&pwd)
39 .stdout(stdout_file)
40 .stderr(stderr_file)
41 // AQUÍ está el cambio principal: Pasamos la lógica como un closure
42 .privileged_action(move || {
43
44 // --- INICIO CÓDIGO DEL DAEMON ---
45
46 // A. Configurar manejo de señales para parada limpia (SIGTERM / SIGINT)
47 let term = Arc::new(AtomicBool::new(false));
48 flag::register(SIGTERM, Arc::clone(&term))?; // Systemd Stop
49 flag::register(SIGINT, Arc::clone(&term))?; // Ctrl+C (Manual)
50
51 println!("[Ticker] Servicio iniciado. PID: {}", std::process::id());
52
53 let frases = [
54 "Estan vivos",
55 "I have no mouth",
56 "I must scream",
57 "Hello world",
58 "Adios mundo :0"
59 ];
60
61 let mut i = 0;
62
63 // B. Bucle principal que respeta la señal de parada
64 while !term.load(Ordering::Relaxed) {
65 let frase = frases[i % frases.len()];
66
67 // C. Usamos println!: La librería ya redirigió esto al archivo .log
68 println!("[Ticker] Ping #{} - {}", i, frase);
69
70 i += 1;
71
72 // Dormir en intervalos cortos para revisar la señal de parada frecuentemente
73 thread::sleep(Duration::from_secs(3));
74 }
75
76 println!("[Ticker] Señal de parada recibida. Cerrando limpiamente.");
77 Ok(())
78 });
79
80 // 4. Arrancar usando la lógica refactorizada (Systemd o Fork)
81 // Nota: Usamos la función del módulo unix directamente
82 daemon_forge::ForgeDaemon::start(daemon)?;
83
84 Ok(())
85}