printnanny_dbus/systemd1/
models.rs

1use std::str::FromStr;
2
3use serde::{Deserialize, Serialize};
4use zbus_systemd::systemd1::UnitProxy;
5
6use crate::error::SystemdError;
7use printnanny_asyncapi_models;
8
9pub const PRINTNANNY_RECORDING_SERVICE_TEMPLATE: &str = "printnanny-recording-sync@";
10
11/// State value that reflects whether the configuration file of this unit has been loaded
12/// https://www.freedesktop.org/wiki/Software/systemd/dbus/ LoadState property
13#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
14pub enum SystemdLoadState {
15    #[serde(rename = "loaded")]
16    Loaded,
17    #[serde(rename = "error")]
18    Error,
19    #[serde(rename = "masked")]
20    Masked,
21    #[serde(rename = "not-found")]
22    NotFound,
23}
24
25impl FromStr for SystemdLoadState {
26    type Err = SystemdError;
27    fn from_str(input: &str) -> Result<SystemdLoadState, Self::Err> {
28        match input {
29            "loaded" => Ok(SystemdLoadState::Loaded),
30            "error" => Ok(SystemdLoadState::Error),
31            "masked" => Ok(SystemdLoadState::Masked),
32            "not-found" => Ok(SystemdLoadState::NotFound),
33            _ => Err(SystemdError::InvalidUnitLoadState {
34                state: input.to_string(),
35            }),
36        }
37    }
38}
39
40/// State value that reflects whether the configuration file of this unit has been loaded
41/// https://www.freedesktop.org/wiki/Software/systemd/dbus/ ActiveState property
42#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
43pub enum SystemdActiveState {
44    #[serde(rename = "active")]
45    Active,
46    #[serde(rename = "activating")]
47    Activating,
48    #[serde(rename = "deactivating")]
49    Deactivating,
50    #[serde(rename = "failed")]
51    Failed,
52    #[serde(rename = "inactive")]
53    Inactive,
54    #[serde(rename = "reloading")]
55    Reloading,
56    #[serde(rename = "loaded")]
57    Loaded,
58}
59
60impl FromStr for SystemdActiveState {
61    type Err = SystemdError;
62    fn from_str(input: &str) -> Result<SystemdActiveState, Self::Err> {
63        match input {
64            "active" => Ok(SystemdActiveState::Active),
65            "activating" => Ok(SystemdActiveState::Activating),
66            "deactivating" => Ok(SystemdActiveState::Deactivating),
67            "failed" => Ok(SystemdActiveState::Failed),
68            "inactive" => Ok(SystemdActiveState::Inactive),
69            "reloading" => Ok(SystemdActiveState::Reloading),
70            "loaded" => Ok(SystemdActiveState::Loaded),
71            _ => Err(SystemdError::InvalidUnitActiveState {
72                state: input.to_string(),
73            }),
74        }
75    }
76}
77
78/// encodes the install state of the unit file of FragmentPath.
79/// https://www.freedesktop.org/wiki/Software/systemd/dbus/ UnitFileState property
80#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
81pub enum SystemdUnitFileState {
82    #[serde(rename = "enabled")]
83    Enabled,
84    #[serde(rename = "enabled-runtime")]
85    EnabledRuntime,
86    #[serde(rename = "linked")]
87    Linked,
88    #[serde(rename = "linked-runtime")]
89    LinkedRuntime,
90    #[serde(rename = "masked")]
91    Masked,
92    #[serde(rename = "masked-runtime")]
93    MaskedRuntime,
94    #[serde(rename = "static")]
95    Static,
96    #[serde(rename = "disabled")]
97    Disabled,
98    #[serde(rename = "invalid")]
99    Invalid,
100}
101
102impl FromStr for SystemdUnitFileState {
103    type Err = SystemdError;
104    fn from_str(input: &str) -> Result<SystemdUnitFileState, Self::Err> {
105        match input {
106            "enabled" => Ok(SystemdUnitFileState::Enabled),
107            "enabled-runtime" => Ok(SystemdUnitFileState::EnabledRuntime),
108            "linked" => Ok(SystemdUnitFileState::Linked),
109            "linked-runtime" => Ok(SystemdUnitFileState::LinkedRuntime),
110            "masked" => Ok(SystemdUnitFileState::Masked),
111            "masked-runtime" => Ok(SystemdUnitFileState::MaskedRuntime),
112            "static" => Ok(SystemdUnitFileState::Static),
113            "disabled" => Ok(SystemdUnitFileState::Disabled),
114            "invalid" => Ok(SystemdUnitFileState::Invalid),
115            _ => Err(SystemdError::InvalidUnitFileState {
116                state: input.to_string(),
117            }),
118        }
119    }
120}
121
122/// encodes states of the same state machine that ActiveState covers, but knows more fine-grained states that are unit-type-specific.
123/// https://www.freedesktop.org/wiki/Software/systemd/dbus/ SubState property
124#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
125pub enum SystemdSubState {}
126
127#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
128pub struct SystemdUnit {
129    // TODO
130    // pub sub_state: SystemdSubSubState, // encodes states of the same state machine that ActiveState covers, but knows more fine-grained states that are unit-type-specific.
131    pub id: String,
132    pub fragment_path: String,
133    pub load_state: SystemdLoadState, // state value that reflects whether the configuration file of this unit has been loaded
134    pub load_error: (String, String), // a pair of strings. If the unit failed to load (as encoded in LoadState, see above), then this will include a D-Bus error pair consisting of the error ID and an explanatory human readable string of what happened. If it loaded successfully, this will be a pair of empty strings.
135    pub active_state: SystemdActiveState, // a state value that reflects whether the unit is currently active or not
136    pub unit_file_state: SystemdUnitFileState, // encodes the install state of the unit file of FragmentPath.
137}
138
139impl SystemdUnit {
140    pub async fn from_owned_object_path(
141        path: zbus::zvariant::OwnedObjectPath,
142    ) -> Result<SystemdUnit, SystemdError> {
143        let connection = zbus::Connection::system().await?;
144        let unit = UnitProxy::new(&connection, path.clone()).await?;
145
146        let unit_file_state = unit.unit_file_state().await?;
147        let load_path = unit.load_state().await?;
148        let active_state = unit.active_state().await?;
149
150        let load_state = SystemdLoadState::from_str(&load_path)?;
151        if load_state == SystemdLoadState::NotFound {
152            return Err(SystemdError::UnitNotFound {
153                unit: path.to_string(),
154            });
155        }
156
157        let result = SystemdUnit {
158            load_state,
159            id: unit.id().await?,
160            fragment_path: unit.fragment_path().await?,
161            active_state: SystemdActiveState::from_str(&active_state)?,
162            unit_file_state: SystemdUnitFileState::from_str(&unit_file_state)?,
163            load_error: unit.load_error().await?,
164        };
165
166        Ok(result)
167    }
168}
169
170impl From<SystemdUnit> for printnanny_asyncapi_models::SystemdUnit {
171    fn from(unit: SystemdUnit) -> printnanny_asyncapi_models::SystemdUnit {
172        let active_state = match unit.active_state {
173            SystemdActiveState::Active => {
174                printnanny_asyncapi_models::SystemdUnitActiveState::Active
175            }
176            SystemdActiveState::Loaded => {
177                printnanny_asyncapi_models::SystemdUnitActiveState::Loaded
178            }
179            SystemdActiveState::Activating => {
180                printnanny_asyncapi_models::SystemdUnitActiveState::Activating
181            }
182            SystemdActiveState::Inactive => {
183                printnanny_asyncapi_models::SystemdUnitActiveState::Inactive
184            }
185            SystemdActiveState::Reloading => {
186                printnanny_asyncapi_models::SystemdUnitActiveState::Reloading
187            }
188            SystemdActiveState::Deactivating => {
189                printnanny_asyncapi_models::SystemdUnitActiveState::Deactivating
190            }
191            SystemdActiveState::Failed => {
192                printnanny_asyncapi_models::SystemdUnitActiveState::Failed
193            }
194        };
195
196        let load_state = match unit.load_state {
197            SystemdLoadState::Masked => printnanny_asyncapi_models::SystemdUnitLoadState::Masked,
198            SystemdLoadState::Error => printnanny_asyncapi_models::SystemdUnitLoadState::Error,
199            SystemdLoadState::Loaded => printnanny_asyncapi_models::SystemdUnitLoadState::Loaded,
200            SystemdLoadState::NotFound => {
201                printnanny_asyncapi_models::SystemdUnitLoadState::NotMinusFound
202            }
203        };
204
205        let unit_file_state = match unit.unit_file_state {
206            SystemdUnitFileState::Enabled => {
207                printnanny_asyncapi_models::SystemdUnitFileState::Enabled
208            }
209            SystemdUnitFileState::EnabledRuntime => {
210                printnanny_asyncapi_models::SystemdUnitFileState::EnabledMinusRuntime
211            }
212            SystemdUnitFileState::Disabled => {
213                printnanny_asyncapi_models::SystemdUnitFileState::Disabled
214            }
215            SystemdUnitFileState::Linked => {
216                printnanny_asyncapi_models::SystemdUnitFileState::Linked
217            }
218            SystemdUnitFileState::LinkedRuntime => {
219                printnanny_asyncapi_models::SystemdUnitFileState::LinkedMinusRuntime
220            }
221            SystemdUnitFileState::Masked => {
222                printnanny_asyncapi_models::SystemdUnitFileState::Masked
223            }
224            SystemdUnitFileState::MaskedRuntime => {
225                printnanny_asyncapi_models::SystemdUnitFileState::MaskedMinusRuntime
226            }
227            SystemdUnitFileState::Static => {
228                printnanny_asyncapi_models::SystemdUnitFileState::Static
229            }
230            SystemdUnitFileState::Invalid => {
231                printnanny_asyncapi_models::SystemdUnitFileState::Invalid
232            }
233        };
234
235        printnanny_asyncapi_models::SystemdUnit {
236            id: unit.id,
237            fragment_path: unit.fragment_path,
238            active_state: Box::new(active_state),
239            load_state: Box::new(load_state),
240            unit_file_state: Box::new(unit_file_state),
241        }
242    }
243}