diff options
| author | Nathan Perry <np@nathanperry.dev> | 2024-08-16 01:28:25 -0400 |
|---|---|---|
| committer | Nathan Perry <np@nathanperry.dev> | 2024-08-16 01:29:31 -0400 |
| commit | a435a926689b0b597caa1c724a91694f74dec778 (patch) | |
| tree | 00085b30f013f969a511a1e1b1666e9c052cb8a6 /src | |
| parent | dabf532d8251063606f0ffcffb0faf5444c46a4a (diff) | |
windows: start postgres svc if not running
Diffstat (limited to 'src')
| -rw-r--r-- | src/bot.rs | 5 | ||||
| -rw-r--r-- | src/lib.rs | 4 | ||||
| -rw-r--r-- | src/windows_util.rs | 129 |
3 files changed, 138 insertions, 0 deletions
@@ -364,6 +364,11 @@ fn after_handle(ctx: PoiseContext) -> BoxFuture<()> { } pub async fn run() -> anyhow::Result<()> { + #[cfg(all(windows, feature = "windows_autostart_postgres"))] + unsafe { + crate::windows_util::ensure_postgres_started()?; + }; + let token = &CONFIG.discord.auth.token; let sb_config = songbird::Config::default(); @@ -1,5 +1,6 @@ #![feature(try_blocks)] #![feature(let_chains)] +#![feature(maybe_uninit_slice)] #[cfg(feature = "db")] pub mod db; @@ -20,6 +21,9 @@ pub mod config; pub mod log_setup; pub mod util; +#[cfg(windows)] +pub mod windows_util; + pub use crate::{ config::*, util::*, diff --git a/src/windows_util.rs b/src/windows_util.rs new file mode 100644 index 0000000..348ea91 --- /dev/null +++ b/src/windows_util.rs @@ -0,0 +1,129 @@ +use windows::{ + core::HSTRING, + Win32::{ + Foundation, + System::Services, + }, +}; + +lazy_static::lazy_static! { + static ref PSQL_REGEX: regex::Regex = regex::Regex::new(r#"^(?:postgresql|psql|postgres)-.*([\d\.]*)"#).unwrap(); +} + +pub unsafe fn ensure_postgres_started() -> windows::core::Result<()> { + let sc_manager = Services::OpenSCManagerW( + None, + None, + (Foundation::GENERIC_READ | Foundation::GENERIC_WRITE).0, + )?; + + let services = list_services(sc_manager)?; + + let mut psql_services = + services.into_iter().filter(|status| PSQL_REGEX.is_match(&status.name)).collect::<Vec<_>>(); + + match psql_services.len() { + 1 => {}, + + 0 => { + log::warn!("unable to identify an installed postgres service"); + }, + + other => { + log::warn!("unable to identify postgres service: {other} potential matches found"); + return Ok(()); + }, + } + + let svc = psql_services.remove(0); + log::debug!("identified postgres service: {}", svc.name); + + match svc.status.dwCurrentState { + Services::SERVICE_RUNNING => { + log::info!("postgres was already running, done"); + return Ok(()); + }, + + Services::SERVICE_START_PENDING => { + log::info!("postgres was already in startup, done"); + return Ok(()); + }, + + _ => { + log::info!("postgres is not running: starting it") + }, + } + + let service = + Services::OpenServiceW(sc_manager, &HSTRING::from(&svc.name), Services::SERVICE_START)?; + + Services::StartServiceW(service, None)?; + + log::info!("started postgres service"); + + Services::CloseServiceHandle(service)?; + Services::CloseServiceHandle(sc_manager)?; + + Ok(()) +} + +const RESULT_SIZE: usize = size_of::<Services::ENUM_SERVICE_STATUS_PROCESSW>(); + +pub struct ServiceStatus { + pub display_name: String, + pub name: String, + pub status: Services::SERVICE_STATUS_PROCESS, +} + +pub unsafe fn list_services( + sc_manager: Services::SC_HANDLE, +) -> windows::core::Result<Vec<ServiceStatus>> { + let mut bytes_needed: u32 = 0; + let mut services_returned: u32 = 0; + let mut resume = 0; + + let mut svcs = vec![]; + + loop { + let mut data = [0u8; 256 * 1024]; + + let result = Services::EnumServicesStatusExW( + sc_manager, + Services::SC_ENUM_PROCESS_INFO, + Services::SERVICE_WIN32, + Services::SERVICE_STATE_ALL, + Some(&mut data), + &mut bytes_needed as *mut _, + &mut services_returned as *mut _, + Some(&mut resume), + None, + ); + + if let Err(ref e) = result + && e.code() != Foundation::ERROR_MORE_DATA.to_hresult() + { + return result.map(|_| unreachable!()); + } + + let data = bytemuck::cast_slice::<u8, [u8; RESULT_SIZE]>( + &data[..services_returned as usize * RESULT_SIZE], + ); + + let elems = data + .into_iter() + .map(|x| core::mem::transmute::<_, Services::ENUM_SERVICE_STATUS_PROCESSW>(*x)) + .map(|x| ServiceStatus { + display_name: x.lpDisplayName.to_string().unwrap(), + name: x.lpServiceName.to_string().unwrap(), + status: x.ServiceStatusProcess, + }); + + svcs.extend(elems); + + if result.is_ok() { + break; + } + } + + Ok(svcs) +} |
