server_manager/manager/impl.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
use crate::*;
impl<F, Fut> ServerManager<F>
where
F: Fn() -> Fut,
Fut: std::future::Future<Output = ()>,
{
/// Title: Create a new ServerManager instance
///
/// Parameters:
/// - `config`: The server configuration containing PID file path and log paths.
/// - `server_fn`: A closure representing the asynchronous server function.
///
/// Returns:
/// - `ServerManager<F>`: A new instance of ServerManager.
pub fn new(config: ServerManagerConfig, server_fn: F) -> Self {
Self { config, server_fn }
}
/// Title: Start the server in foreground mode
///
/// Parameters:
/// - None
///
/// Returns:
/// - `()`: No return value.
///
/// This function writes the current process ID to the PID file specified in the configuration
/// and then runs the server function asynchronously.
pub async fn start(&self) {
if let Err(e) = self.write_pid_file() {
eprintln!("Failed to write pid file: {}", e);
return;
}
(self.server_fn)().await;
}
/// Title: Stop the server
///
/// Parameters:
/// - None
///
/// Returns:
/// - `Result<(), Box<dyn std::error::Error>>`: Operation result.
///
/// This function reads the process ID from the PID file and attempts to kill the process using a SIGTERM signal.
pub fn stop(&self) -> Result<(), Box<dyn Error>> {
let pid: i32 = self.read_pid_file()?;
self.kill_process(pid)
}
/// Title: Start the server in daemon (background) mode on Unix platforms
///
/// Parameters:
/// - None
///
/// Returns:
/// - `Result<(), Box<dyn std::error::Error>>`: Operation result.
///
/// This function uses the daemonize crate to run the server process in the background. It configures
/// the PID file, stdout log, and stderr log paths from the configuration.
#[cfg(unix)]
pub fn start_daemon(&self) -> Result<(), Box<dyn Error>> {
let stdout_file = fs::File::create(&self.config.stdout_log)?;
let stderr_file = fs::File::create(&self.config.stderr_log)?;
let daemonize_obj = Daemonize::new()
.pid_file(&self.config.pid_file)
.chown_pid_file(true)
.working_directory(".")
.umask(0o027)
.stdout(stdout_file)
.stderr(stderr_file);
daemonize_obj.start()?;
let rt = tokio::runtime::Runtime::new()?;
rt.block_on(async {
(self.server_fn)().await;
});
Ok(())
}
/// Title: Start the server in daemon mode on non-Unix platforms
///
/// Parameters:
/// - None
///
/// Returns:
/// - `Result<(), Box<dyn std::error::Error>>`: Operation result.
///
/// This function returns an error because daemon mode is not supported on non-Unix platforms.
#[cfg(not(unix))]
pub fn start_daemon(&self) -> Result<(), Box<dyn Error>> {
Err("Daemon mode is not supported on non-Unix platforms".into())
}
/// Title: Read process ID from the PID file
///
/// Parameters:
/// - None
///
/// Returns:
/// - `Result<i32, Box<dyn std::error::Error>>`: The process ID if successful.
///
/// This function reads the content of the PID file specified in the configuration and parses it as an integer.
fn read_pid_file(&self) -> Result<i32, Box<dyn Error>> {
let pid_str: String = fs::read_to_string(&self.config.pid_file)?;
let pid: i32 = pid_str.trim().parse::<i32>()?;
Ok(pid)
}
/// Title: Write current process ID to the PID file
///
/// Parameters:
/// - None
///
/// Returns:
/// - `Result<(), Box<dyn std::error::Error>>`: Operation result.
///
/// This function obtains the current process ID and writes it as a string to the PID file specified in the configuration.
fn write_pid_file(&self) -> Result<(), Box<dyn Error>> {
let pid: u32 = process::id();
fs::write(&self.config.pid_file, pid.to_string())?;
Ok(())
}
/// Title: Kill process by PID on Unix platforms
///
/// Parameters:
/// - `pid`: The process ID to kill.
///
/// Returns:
/// - `Result<(), Box<dyn std::error::Error>>`: Operation result.
///
/// This function sends a SIGTERM signal to the process with the given PID using libc::kill.
#[cfg(unix)]
fn kill_process(&self, pid: i32) -> Result<(), Box<dyn Error>> {
let result = unsafe { libc::kill(pid as libc::pid_t, libc::SIGTERM) };
if result == 0 {
Ok(())
} else {
Err(format!("Failed to kill process with pid: {}", pid).into())
}
}
/// Title: Kill process by PID on non-Unix platforms
///
/// Parameters:
/// - `pid`: The process ID to kill.
///
/// Returns:
/// - `Result<(), Box<dyn std::error::Error>>`: Operation result.
///
/// This function returns an error because killing a process is not supported on non-Unix platforms.
#[cfg(not(unix))]
fn kill_process(&self, _pid: i32) -> Result<(), Box<dyn Error>> {
Err("kill_process is not supported on non-Unix platforms".into())
}
}