1use reqwest::Client;
2use thiserror::Error;
3use url::Url;
4
5#[derive(Debug, Error)]
6pub enum PduDaemonError {
7 #[error("Could not parse url: {0}")]
8 ParseUrlError(#[from] url::ParseError),
9 #[error("Http request failed: {0}")]
10 ReqwestError(#[from] reqwest::Error),
11}
12
13#[derive(Debug, Clone)]
14pub struct PduDaemon {
15 client: Client,
16 url: Url,
17}
18
19impl PduDaemon {
20 pub fn new(url: &str) -> Result<Self, PduDaemonError> {
22 let client = Client::new();
23 let url = url.parse()?;
24 Ok(Self { client, url })
25 }
26
27 fn build_url(&self, command: &str, hostname: &str, port: &str) -> Result<Url, PduDaemonError> {
28 let mut url = self.url.join("power/control/")?.join(command)?;
29
30 url.query_pairs_mut()
31 .append_pair("hostname", hostname)
32 .append_pair("port", port);
33 Ok(url)
34 }
35
36 async fn send(&self, url: Url) -> Result<(), PduDaemonError> {
37 self.client.get(url).send().await?.error_for_status()?;
38 Ok(())
39 }
40
41 pub async fn on(&self, hostname: &str, port: &str) -> Result<(), PduDaemonError> {
43 let url = self.build_url("on", hostname, port)?;
44 self.send(url).await
45 }
46
47 pub async fn off(&self, hostname: &str, port: &str) -> Result<(), PduDaemonError> {
49 let url = self.build_url("off", hostname, port)?;
50 self.send(url).await
51 }
52
53 pub async fn reboot(
55 &self,
56 hostname: &str,
57 port: &str,
58 delay: Option<u32>,
59 ) -> Result<(), PduDaemonError> {
60 let mut url = self.build_url("reboot", hostname, port)?;
61 if let Some(delay) = delay {
62 url.query_pairs_mut()
63 .append_pair("delay", &delay.to_string());
64 }
65 self.send(url).await
66 }
67}