i3status_rs/blocks/
docker.rs1use super::prelude::*;
34use std::path::Path;
35use tokio::net::UnixStream;
36
37#[derive(Deserialize, Debug, SmartDefault)]
38#[serde(deny_unknown_fields, default)]
39pub struct Config {
40 #[default(5.into())]
41 pub interval: Seconds,
42 pub format: FormatConfig,
43 #[default("/var/run/docker.sock".into())]
44 pub socket_path: ShellString,
45}
46
47pub async fn run(config: &Config, api: &CommonApi) -> Result<()> {
48 let format = config.format.with_default(" $icon $running.eng(w:1) ")?;
49 let socket_path = config.socket_path.expand()?;
50
51 loop {
52 let status = Status::new(&*socket_path).await?;
53
54 let mut widget = Widget::new().with_format(format.clone());
55 widget.set_values(map! {
56 "icon" => Value::icon("docker"),
57 "total" => Value::number(status.total),
58 "running" => Value::number(status.running),
59 "paused" => Value::number(status.paused),
60 "stopped" => Value::number(status.stopped),
61 "images" => Value::number(status.images),
62 });
63 api.set_widget(widget)?;
64
65 select! {
66 _ = sleep(config.interval.0) => (),
67 _ = api.wait_for_update_request() => (),
68 }
69 }
70}
71
72#[derive(Deserialize, Debug)]
73struct Status {
74 #[serde(rename = "Containers")]
75 total: i64,
76 #[serde(rename = "ContainersRunning")]
77 running: i64,
78 #[serde(rename = "ContainersStopped")]
79 stopped: i64,
80 #[serde(rename = "ContainersPaused")]
81 paused: i64,
82 #[serde(rename = "Images")]
83 images: i64,
84}
85
86impl Status {
87 async fn new(socket_path: impl AsRef<Path>) -> Result<Self> {
88 let socket = UnixStream::connect(socket_path)
89 .await
90 .error("Failed to connect to socket")?;
91 let (mut request_sender, connection) = hyper::client::conn::handshake(socket)
92 .await
93 .error("Failed to create request sender")?;
94 tokio::spawn(connection);
95 let request = hyper::Request::builder()
96 .header("Host", "localhost")
97 .uri("http://api/info")
98 .method("GET")
99 .body(hyper::Body::empty())
100 .error("Failed to create request")?;
101 let response = request_sender
102 .send_request(request)
103 .await
104 .error("Failed to get response")?;
105 let bytes = hyper::body::to_bytes(response.into_body())
106 .await
107 .error("Failed to get response bytes")?;
108 serde_json::from_slice::<Self>(&bytes).error("Failed to deserialize JSON")
109 }
110}