hatchery_server/
subservice.rs1use crate::error::ServerError;
4use serde::Serialize;
5use std::process::Stdio;
6use tokio::process::{Child, Command};
7
8#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize)]
9#[serde(rename_all = "kebab-case")]
10pub enum State {
11 Stopped,
12 Running,
13 Failed,
14}
15
16#[derive(Clone, Debug, Serialize)]
17pub struct Status {
18 pub name: &'static str,
19 pub state: State,
20 pub port: Option<u16>,
22 pub detail: Option<String>,
23}
24
25pub trait Subservice: Send {
28 fn name(&self) -> &'static str;
29 fn on_demand(&self) -> bool {
30 false
31 }
32 fn start(&mut self) -> Result<(), ServerError>;
33 fn stop(&mut self);
34 fn status(&mut self) -> Status;
35}
36
37pub struct ManagedProcess {
39 child: Option<Child>,
40}
41
42impl ManagedProcess {
43 pub fn new() -> Self {
44 Self { child: None }
45 }
46
47 pub fn spawn(&mut self, mut command: Command) -> Result<(), ServerError> {
48 command.stdin(Stdio::null()).kill_on_drop(true);
49 let child = command.spawn()?;
50 self.child = Some(child);
51 Ok(())
52 }
53
54 pub fn alive(&mut self) -> bool {
56 match self.child.as_mut().map(Child::try_wait) {
57 Some(Ok(None)) => true,
58 Some(_) => {
59 self.child = None;
60 false
61 }
62 None => false,
63 }
64 }
65
66 pub fn stop(&mut self) {
68 if let Some(mut child) = self.child.take() {
69 let _ = child.start_kill();
70 }
71 }
72}
73
74impl Default for ManagedProcess {
75 fn default() -> Self {
76 Self::new()
77 }
78}