diff options
| author | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-05-10 22:09:32 +0300 |
|---|---|---|
| committer | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-05-10 22:09:32 +0300 |
| commit | d284819e4c8ec01d53ac47fbd5aaf03d3ac52f1c (patch) | |
| tree | 304bc0854d0e1a20cb10d2f81fb58c08633741c3 /src/server | |
| parent | 77e1cc8f04a8b518557f93494ed634aee5f037e2 (diff) | |
fix: make update server stop safer
Diffstat (limited to 'src/server')
| -rw-r--r-- | src/server/autodetect.rs | 81 |
1 files changed, 5 insertions, 76 deletions
diff --git a/src/server/autodetect.rs b/src/server/autodetect.rs index 7cd505fb..fd48de9b 100644 --- a/src/server/autodetect.rs +++ b/src/server/autodetect.rs @@ -8,7 +8,7 @@ //! The `--no-session` flag bypasses server/client entirely and runs monolithically //! (escape hatch for users who want the traditional single-process behavior). -use std::io::{self, BufRead, BufReader, Write}; +use std::io; use std::os::unix::net::UnixStream; use std::os::unix::process::CommandExt; use std::path::Path; @@ -46,12 +46,6 @@ pub fn is_server_listening() -> bool { is_server_listening_at(&client_socket_path()) } -#[derive(Debug, Clone, PartialEq, Eq)] -struct ServerStatus { - version: Option<String>, - protocol: Option<u32>, -} - /// Checks whether a herdr server is listening at a specific socket path. fn is_server_listening_at(socket_path: &Path) -> bool { if !socket_path.exists() { @@ -86,74 +80,8 @@ fn is_server_listening_at(socket_path: &Path) -> bool { } } -fn read_server_status_at( - socket_path: &Path, - timeout: Duration, -) -> io::Result<Option<ServerStatus>> { - use crate::api::schema::{Method, PingParams, Request}; - - if !socket_path.exists() { - return Ok(None); - } - - let mut stream = match UnixStream::connect(socket_path) { - Ok(stream) => stream, - Err(err) - if matches!( - err.kind(), - io::ErrorKind::ConnectionRefused - | io::ErrorKind::NotFound - | io::ErrorKind::TimedOut - ) => - { - return Ok(None); - } - Err(err) => return Err(err), - }; - - stream.set_write_timeout(Some(timeout))?; - stream.set_read_timeout(Some(timeout))?; - - let request = Request { - id: "autodetect:server:status".into(), - method: Method::Ping(PingParams::default()), - }; - stream.write_all(serde_json::to_string(&request)?.as_bytes())?; - stream.write_all(b"\n")?; - stream.flush()?; - - let mut reader = BufReader::new(stream); - let mut line = String::new(); - let read = reader.read_line(&mut line)?; - if read == 0 || line.trim().is_empty() { - return Err(io::Error::new( - io::ErrorKind::UnexpectedEof, - "empty server status response", - )); - } - - let response: serde_json::Value = serde_json::from_str(&line).map_err(io::Error::other)?; - if response.get("error").is_some() { - return Err(io::Error::other(format!( - "server status request failed: {response}" - ))); - } - - let result = &response["result"]; - Ok(Some(ServerStatus { - version: result - .get("version") - .and_then(|value| value.as_str()) - .map(str::to_owned), - protocol: result - .get("protocol") - .and_then(|value| value.as_u64()) - .and_then(|value| u32::try_from(value).ok()), - })) -} - -fn read_server_status() -> io::Result<Option<ServerStatus>> { - read_server_status_at(&crate::api::socket_path(), STATUS_REQUEST_TIMEOUT) +fn read_server_status() -> io::Result<Option<crate::api::RuntimeStatus>> { + crate::api::read_runtime_status_at(&crate::api::socket_path(), STATUS_REQUEST_TIMEOUT) } fn validate_running_server_compatibility() -> io::Result<()> { @@ -306,6 +234,7 @@ pub fn auto_detect_launch() -> io::Result<()> { mod tests { use super::*; use std::ffi::OsStr; + use std::io::{BufRead, BufReader, Write}; use std::os::unix::net::UnixListener; use std::sync::{Mutex, OnceLock}; @@ -470,7 +399,7 @@ mod tests { stream.flush().unwrap(); }); - let status = read_server_status_at(&path, Duration::from_millis(200)) + let status = crate::api::read_runtime_status_at(&path, Duration::from_millis(200)) .unwrap() .unwrap(); let _ = handle.join(); |
