async_i3ipc/
lib.rs

1#![doc(html_root_url = "https://docs.rs/async-i3ipc/0.7.0")]
2//! # async-i3ipc
3//!
4//! This crate provides types and functions for working with i3's IPC protocol
5//! in an async context and with async-std (tokio version [here](https://docs.rs/crate/tokio-i3ipc)). It re-exports the subcrate `i3ipc-types`
6//! because it is also used for a synchronous implementation of the protocol.
7//!
8//! This library follows a similar API to the synchronous version. All important
9//! functions live on the [I3](struct.I3.html) type. You must first `await` a
10//! [connect](struct.I3.html#method.connect) call, then you can execute
11//! commands, send/read messages from i3, or subscribe to listen to `Event`s.
12//!
13//! ## Subscribe & Listen
14//!
15//! ```rust,no_run
16//! use std::io;
17//! use async_i3ipc::{
18//!     event::{Event, Subscribe},
19//!     I3,
20//! };
21//!
22//! #[async_std::main]
23//! async fn main() -> io::Result<()> {
24//!     let mut i3 = I3::connect().await?;
25//!     let resp = i3.subscribe([Subscribe::Window]).await?;
26//!
27//!     println!("{:#?}", resp);
28//!     let mut listener = i3.listen();
29//!     while let Ok(event) = listener.next().await {
30//!         match event {
31//!             Event::Workspace(ev) => println!("workspace change event {:?}", ev),
32//!             Event::Window(ev) => println!("window event {:?}", ev),
33//!             Event::Output(ev) => println!("output event {:?}", ev),
34//!             Event::Mode(ev) => println!("mode event {:?}", ev),
35//!             Event::BarConfig(ev) => println!("bar config update {:?}", ev),
36//!             Event::Binding(ev) => println!("binding event {:?}", ev),
37//!             Event::Shutdown(ev) => println!("shutdown event {:?}", ev),
38//!             Event::Tick(ev) => println!("tick event {:?}", ev),
39//!         }
40//!     }
41//!     Ok(())
42//! }
43//! ```
44//!
45//! ## Sending/Reading from I3
46//!
47//! To [send messages](https://i3wm.org/docs/ipc.html#_sending_messages_to_i3) to i3,
48//! call any of the `get_*` functions on [I3](struct.I3.html).
49//!
50//! ```no_run
51//! use std::io;
52//! use async_i3ipc::{reply, I3};
53//!
54//! #[async_std::main]
55//! async fn main() -> io::Result<()> {
56//!     let mut i3 = I3::connect().await?;
57//!     // this type can be inferred, here is written explicitly:
58//!     let tree: reply::Node = i3.get_tree().await?;
59//!     println!("{:#?}", tree);
60//!
61//!     Ok(())
62//! }
63//! ```
64//!
65//! All the `get_*` functions on [I3](struct.I3.html) are simple wrappers around
66//! two main async functions. You could write any of them yourself, in fact:
67//! ```no_run
68//! # use std::io;
69//! use async_i3ipc::{msg, reply, MsgResponse, I3};
70//!
71//! #[async_std::main]
72//! # async fn main() -> io::Result<()> {
73//! let mut i3 = I3::connect().await?;
74//! // send msg RunCommand with a payload
75//! let payload = "some_command";
76//! i3.send_msg_body(msg::Msg::RunCommand, payload).await?;
77//! let resp: MsgResponse<Vec<reply::Success>> = i3.read_msg().await?;
78//! # Ok(())
79//! # }
80//! ```
81pub use i3ipc_types::*;
82pub mod stream;
83mod util;
84
85pub use stream::EventStream;
86pub use util::*;
87
88use async_std::{os::unix::net::UnixStream, prelude::*};
89use serde::de::DeserializeOwned;
90use std::io;
91
92/// Newtype wrapper for `UnixStream` that implements i3's IPC
93#[derive(Debug)]
94pub struct I3 {
95    stream: UnixStream,
96}
97
98// Implement `Future` for [I3](struct.I3.html) so it can be polled into a ready
99// `UnixStream`
100impl I3 {
101    /// Sends a message and payload, used for `get_*` commands and `run_command`
102    async fn _send_msg<P>(&mut self, msg: msg::Msg, payload: Option<P>) -> io::Result<()>
103    where
104        P: AsRef<str>,
105    {
106        let buf = self.stream._encode_msg(msg, payload);
107        self.stream.write_all(&buf).await
108    }
109
110    async fn _decode_msg(&mut self) -> io::Result<(u32, Vec<u8>)> {
111        let mut init = [0_u8; 14];
112        self.stream.read_exact(&mut init).await?;
113
114        assert!(&init[0..6] == MAGIC.as_bytes(), "Magic str not received");
115        let payload_len = u32::from_ne_bytes([init[6], init[7], init[8], init[9]]) as usize;
116        let msg_type = u32::from_ne_bytes([init[10], init[11], init[12], init[13]]);
117
118        let mut payload = vec![0_u8; payload_len];
119        self.stream.read_exact(&mut payload).await?;
120
121        Ok((msg_type, payload))
122    }
123
124    /// Connects to I3 over `UnixStream`
125    pub async fn connect() -> io::Result<Self> {
126        Ok(I3 {
127            stream: UnixStream::connect(socket_path()?).await?,
128        })
129    }
130
131    pub async fn send_msg_body<P>(&mut self, msg: msg::Msg, payload: P) -> io::Result<()>
132    where
133        P: AsRef<str>,
134    {
135        self._send_msg(msg, Some(payload)).await
136    }
137
138    pub async fn send_msg(&mut self, msg: msg::Msg) -> io::Result<()> {
139        self._send_msg::<&str>(msg, None).await
140    }
141
142    /// Receive some message from the socket. Holds a `Msg` type and payload
143    pub async fn read_msg<D>(&mut self) -> io::Result<MsgResponse<D>>
144    where
145        D: DeserializeOwned,
146    {
147        let (msg_type, payload) = self._decode_msg().await?;
148        Ok(MsgResponse {
149            msg_type: msg_type.into(),
150            body: serde_json::from_slice(&payload[..])?,
151        })
152    }
153
154    /// Like `read_msg` but for `event::Event`
155    pub async fn read_event(&mut self) -> io::Result<event::Event> {
156        let (evt_type, payload_bytes) = self._decode_msg().await?;
157        decode_event(evt_type, payload_bytes)
158    }
159
160    /// Send a `Msg` and payload and receive a response. Convenience function
161    /// over `send_msg` and `read_msg`
162    pub async fn send_read<P, D>(&mut self, msg: msg::Msg, payload: P) -> io::Result<MsgResponse<D>>
163    where
164        P: AsRef<str>,
165        D: DeserializeOwned,
166    {
167        self.send_msg_body(msg, payload).await?;
168        self.read_msg().await
169    }
170
171    /// Returns a Future that will send a [Subscribe](event/enum.Subscribe.html)
172    /// message to i3 along with a list of events to listen to.
173    pub async fn subscribe<E>(&mut self, events: E) -> io::Result<reply::Success>
174    where
175        E: AsRef<[event::Subscribe]>,
176    {
177        let sub_json = serde_json::to_string(events.as_ref())?;
178        self.send_msg_body(msg::Msg::Subscribe, sub_json).await?;
179        Ok(self.read_msg::<reply::Success>().await?.body)
180    }
181
182    /// Provides a type that implements `Stream` so you can `await` events in a
183    /// loop
184    pub fn listen(self) -> EventStream {
185        EventStream::new(self.stream)
186    }
187
188    /// Run an arbitrary command on i3. Response is a `Vec` of success
189    /// true/false.
190    pub async fn run_command<S: AsRef<str>>(
191        &mut self,
192        payload: S,
193    ) -> io::Result<Vec<reply::Success>> {
194        self.send_msg_body(msg::Msg::RunCommand, payload).await?;
195        Ok(self.read_msg().await?.body)
196    }
197
198    /// Future for getting the current
199    /// [Workspaces](../reply/struct.Workspace.html), sends
200    /// [Workspaces](../msg/enum.Msg.html#variant.Workspaces)
201    pub async fn get_workspaces(&mut self) -> io::Result<reply::Workspaces> {
202        self.send_msg(msg::Msg::Workspaces).await?;
203        let resp: MsgResponse<Vec<reply::Workspace>> = self.read_msg().await?;
204        Ok(resp.body)
205    }
206
207    /// Future that gets all [Outputs](../reply/struct.Outputs.html), sends
208    /// [Outputs](../msg/enum.Msg.html#variant.Outputs)
209    pub async fn get_outputs(&mut self) -> io::Result<reply::Outputs> {
210        self.send_msg(msg::Msg::Outputs).await?;
211        Ok(self.read_msg().await?.body)
212    }
213
214    /// Future to get complete [Node](../reply/struct.Node.html), sends
215    /// [Tree](../msg/enum.Msg.html#variant.Tree)
216    pub async fn get_tree(&mut self) -> io::Result<reply::Node> {
217        self.send_msg(msg::Msg::Tree).await?;
218        Ok(self.read_msg().await?.body)
219    }
220
221    /// Get all [Marks](../reply/struct.Marks.html), sends
222    /// [Marks](../msg/enum.Msg.html#variant.Marks)
223    pub async fn get_marks(&mut self) -> io::Result<reply::Marks> {
224        self.send_msg(msg::Msg::Marks).await?;
225        Ok(self.read_msg().await?.body)
226    }
227
228    /// Future to get all [BarIds](../reply/struct.BarIds.html), sends
229    /// [BarConfig](../msg/enum.Msg.html#variant.BarConfig)
230    pub async fn get_bar_ids(&mut self) -> io::Result<reply::BarIds> {
231        self.send_msg(msg::Msg::BarConfig).await?;
232        Ok(self.read_msg().await?.body)
233    }
234
235    /// Future to get configs associated with a bar id responds with
236    /// [BarConfig](../reply/struct.BarConfig.html), sends
237    /// [BarConfig](../msg/enum.Msg.html#variant.BarConfig)
238    pub async fn get_bar_config<S: AsRef<str>>(
239        &mut self,
240        bar_id: S,
241    ) -> io::Result<reply::BarConfig> {
242        self.send_msg_body(msg::Msg::BarConfig, bar_id).await?;
243        Ok(self.read_msg().await?.body)
244    }
245
246    /// Get i3 version
247    pub async fn get_version(&mut self) -> io::Result<reply::Version> {
248        self.send_msg(msg::Msg::Version).await?;
249        Ok(self.read_msg().await?.body)
250    }
251
252    /// Future to get [BindingModes](../reply/struct.BindingModes.html), sends
253    /// [BindingModes](../msg/enum.Msg.html#variant.BindingModes)
254    pub async fn get_binding_modes(&mut self) -> io::Result<reply::BindingModes> {
255        self.send_msg(msg::Msg::BindingModes).await?;
256        Ok(self.read_msg().await?.body)
257    }
258
259    /// Future for [Config](../reply/struct.Config.html), sends
260    /// [Config](../msg/enum.Msg.html#variant.Config)
261    pub async fn get_config(&mut self) -> io::Result<reply::Config> {
262        self.send_msg(msg::Msg::Config).await?;
263        Ok(self.read_msg().await?.body)
264    }
265
266    /// Future sends [Tick](../msg/enum.Msg.html#variant.Tick)
267    pub async fn get_tick(&mut self) -> io::Result<reply::Success> {
268        self.send_msg(msg::Msg::Tick).await?;
269        Ok(self.read_msg().await?.body)
270    }
271
272    /// Future [Sync](../msg/enum.Msg.html#variant.Sync)
273    pub async fn get_sync(&mut self) -> io::Result<reply::Success> {
274        self.send_msg(msg::Msg::Sync).await?;
275        Ok(self.read_msg().await?.body)
276    }
277
278    /// Future to get [BindingState](../reply/struct.BindingState.html), sends
279    /// [BindingState](../msg/enum.Msg.html#variant.BindingState)
280    pub async fn get_binding_state(&mut self) -> io::Result<reply::BindingState> {
281        self.send_msg(msg::Msg::BindingState).await?;
282        Ok(self.read_msg().await?.body)
283    }
284}