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}