1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
//! # tokio-i3ipc //! //! This crate provides types and functions for working with i3's IPC protocol within tokio. It re-exports the subcrate `i3ipc-types` because it is also used for a synchronous version of the code. //! //! There are many ways you can interact with this library. You can import an already written future and simply spawn/run it, or you can use the building blocks to construct your own futures. //! //! # Subscribing //! //! ```should_panic //! # use futures::{ //! # future, //! # sink::Sink, //! # stream::Stream, //! # sync::mpsc::{self, Sender}, //! # Future, //! # }; //! # use std::io; //! use tokio_i3ipc::{subscribe, event::{self, Subscribe}}; //! //! fn main() -> io::Result<()> { //! let mut rt = //! tokio::runtime::current_thread::Runtime::new().expect("Failed building runtime"); //! // create a channel to receive responses //! let (tx, rx) = mpsc::channel(5); //! // pass a handle and `Sender` to `subscribe` //! subscribe(rt.handle(), tx, vec![Subscribe::Window])?; //! // handle the events received on the channel //! let fut = rx.for_each(|e: event::Event| { //! println!("received"); //! println!("{:#?}", e); //! future::ok(()) //! }); //! rt.spawn(fut); //! rt.run().expect("failed runtime"); //! Ok(()) //! } //! ``` //! //! `send_msg`, `write_msg_json` and `write_msg` will handle writing to i3. `read_msg` and `read_msg_and` will handle reading. The latter returns the stream again to continue using it. //! //! ## Sending Messages to i3 //! //! To [send messages](https://i3wm.org/docs/ipc.html#_sending_messages_to_i3) to i3, there are a number of convenience futures that need only be passed a `UnixStream` and then run in your event loop. //! //! ```should_panic //! # use futures::future::Future; //! # use tokio_uds::UnixStream; //! # use tokio; //! use tokio_i3ipc::{I3, Connect, MsgResponse, get, reply}; //! //! fn main() { //! let fut = I3::connect() //! .expect("unable to get socket") //! .and_then(get::get_workspaces) //! .and_then( //! |(_stream, reply): (UnixStream, MsgResponse<reply::Workspaces>)| { //! // do something w/ reply::Workspaces //! futures::future::ok(()) //! }, //! ) //! .map(|_| ()) //! .map_err(|_| ()); //! tokio::run(fut); //! } //! ``` pub use i3ipc_types::*; pub mod codec; pub mod get; pub mod io; mod util; pub use util::*; use futures::{try_ready, Async, Future, Poll}; use std::io as stio; use tokio::io::{AsyncRead, AsyncWrite}; use tokio_uds::{ConnectFuture, UnixStream}; /// Newtype wrapper for `ConnectFuture` meant to resolve some Stream, mostly likely `UnixStream` #[derive(Debug)] pub struct I3 { conn: ConnectFuture, } pub trait Connect { type Connected: AsyncI3IPC; type Error; type Future: Future<Item = Self::Connected, Error = Self::Error>; fn connect() -> stio::Result<Self::Future>; } impl Connect for I3 { type Connected = UnixStream; type Future = ConnectFuture; type Error = stio::Error; fn connect() -> stio::Result<Self::Future> { Ok(UnixStream::connect(socket_path()?)) } } /// [I3IPC](trait.I3IPC.html) provides default implementations for reading/writing buffers into a format i3 understands. This /// trait expresses that + asynchronousity pub trait AsyncI3IPC: AsyncRead + AsyncWrite + I3IPC {} /// Add the default trait to `UnixStream` impl AsyncI3IPC for UnixStream {} impl<'a, T: ?Sized + AsyncI3IPC> AsyncI3IPC for &'a mut T {} impl<T: ?Sized + AsyncI3IPC> AsyncI3IPC for Box<T> {} // Implement `Future` for [I3](struct.I3.html) so it can be polled into a ready `UnixStream` impl Future for I3 where { type Item = UnixStream; type Error = stio::Error; fn poll(&mut self) -> Poll<Self::Item, Self::Error> { let stream = try_ready!(self.conn.poll()); Ok(Async::Ready(stream)) } }