tokio-i3ipc

Build Status Crate API

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 cna 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.

I expect the most common use case will be to subscribe to some events and listen over a channel:

```rust 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::currentthread::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.foreach(|e: event::Event| { println!("received"); println!("{:#?}", e); future::ok(()) }); rt.spawn(fut); rt.run().expect("failed runtime"); Ok(()) } ```

But all the tools are exported to build something like this yourself, interact with i3 in any way you like:

```rust use tokio::codec::FramedRead; use tokio_uds::UnixStream; use futures::{future::Future, stream::Stream, sink::Sink, sync::mpsc::Sender}; use std::io;

use tokioi3ipc::{Connect, subscribefuture, event, I3, codec::EventCodec};

pub fn subscribe( rt: tokio::runtime::currentthread::Handle, tx: Sender, events: Vec, ) -> io::Result<()> { let fut = I3::connect()? .andthen(|stream: UnixStream| subscribefuture(stream, events)) .andthen(|(stream, )| { let framed = FramedRead::new(stream, EventCodec); let sender = framed .foreach(move |evt| { let tx = tx.clone(); tx.send(evt) .map(|| ()) .maperr(|e| io::Error::new(io::ErrorKind::BrokenPipe, e)) }) .maperr(|err| println!("{}", err)); tokio::spawn(sender); Ok(()) }) .map(|| ()) .map_err(|e| eprintln!("{:?}", e));

rt.spawn(fut);
Ok(())

} ```

Another example, getting all displays from i3:

```rust use std::io; use futures::future::Future; use tokio_i3ipc::{get, I3, Connect};

pub fn getdisplays() -> io::Result<()> { let fut = I3::connect()? .andthen(get::getoutputs) .andthen(|resp| { dbg!(resp); Ok(()) }) .map(|| ()) .maperr(|e| println!("{}", e)); Ok(()) } ```

or, you could write get_outputs yourself:

```rust use tokiouds::UnixStream; use futures::future::Future; use std::io; use tokioi3ipc::{reply, msg::Msg, MsgResponse, event, io as i3io};

pub fn getoutputs( stream: UnixStream, ) -> impl Future), Error = io::Error> { i3io::sendmsg(stream, Msg::Outputs).andthen(i3io::readmsg_and) } ```

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 to i3, there are a number of convenience futures that need only be passed a UnixStream and then run in your event loop.

```rust use futures::future::Future; use tokiouds::UnixStream; use tokio; use tokioi3ipc::{I3, Connect, MsgResponse, get, reply};

fn main() { let fut = I3::connect() .expect("unable to get socket") .andthen(get::getworkspaces) .andthen( |(stream, reply): (UnixStream, MsgResponse)| { // do something w/ reply::Workspaces futures::future::ok(()) }, ) .map(|| ()) .maperr(|_| ()); tokio::run(fut); } ```