support_kit/service/
service_control.rs1use service_manager::*;
2use std::ffi::OsString;
3use std::path::PathBuf;
4
5use crate::{Configuration, ServiceControlError};
6
7use super::{ServiceCommand, ServiceName};
8
9pub struct ServiceControl {
10 name: ServiceName,
11 label: ServiceLabel,
12 manager: Box<dyn ServiceManager>,
13}
14
15impl std::fmt::Debug for ServiceControl {
16 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
17 f.debug_struct("ServiceControl")
18 .field("name", &self.name)
19 .field("label", &self.label)
20 .field("manager level", &self.manager.level())
21 .field("manager available", &self.manager.available())
22 .field("program", &self.program())
23 .finish()
24 }
25}
26
27impl ServiceControl {
28 pub fn init(config: &Configuration) -> Result<Self, ServiceControlError> {
29 let mut manager = match config.service.service_manager {
30 Some(manager) => <dyn ServiceManager>::target(manager),
31 None => <dyn ServiceManager>::native()?,
32 };
33
34 if !config.service.system {
35 match manager.set_level(ServiceLevel::User) {
36 Ok(_) => {}
37 Err(_) => {
38 tracing::warn!(
39 "attempted to set user level service manager but failed, \
40 continuing at system level."
41 );
42 }
43 }
44 }
45
46 Ok(Self {
47 name: config.name(),
48 label: config.name().as_default_label()?,
49 manager,
50 })
51 }
52
53 fn program(&self) -> Result<PathBuf, ServiceControlError> {
54 Ok(std::env::current_exe()?)
55 }
56
57 #[tracing::instrument(level = "trace")]
58 pub fn execute(&self, operation: ServiceCommand) -> Result<(), ServiceControlError> {
59 match operation {
60 ServiceCommand::Install(install) => {
61 tracing::trace!(
62 install_args = ?install,
63 "installing with args"
64 );
65
66 self.install(self.program()?, install.args)
67 }
68 ServiceCommand::Start => self.start(),
69 ServiceCommand::Stop => self.stop(),
70 ServiceCommand::Uninstall => self.uninstall(),
71 }?;
72
73 Ok(())
74 }
75
76 #[tracing::instrument(level = "trace")]
77 pub fn install(
78 &self,
79 program: PathBuf,
80 args: Vec<OsString>,
81 ) -> Result<(), ServiceControlError> {
82 self.manager.install(ServiceInstallCtx {
83 label: self.label.clone(),
84 program,
85 args,
86 contents: None,
87 username: None,
88 working_directory: None,
89 environment: None,
90 })?;
91
92 Ok(())
93 }
94
95 #[tracing::instrument(level = "trace")]
96 pub fn start(&self) -> Result<(), ServiceControlError> {
97 self.manager.start(ServiceStartCtx {
98 label: self.label.clone(),
99 })?;
100
101 Ok(())
102 }
103
104 #[tracing::instrument(level = "trace")]
105 pub fn stop(&self) -> Result<(), ServiceControlError> {
106 self.manager.stop(ServiceStopCtx {
107 label: self.label.clone(),
108 })?;
109
110 Ok(())
111 }
112
113 #[tracing::instrument(level = "trace")]
114 pub fn uninstall(&self) -> Result<(), ServiceControlError> {
115 self.manager.uninstall(ServiceUninstallCtx {
116 label: self.label.clone(),
117 })?;
118
119 Ok(())
120 }
121}