swayipc_async/
connection.rs

1use super::common::receive_from_stream;
2use super::socket::get_socketpath;
3use crate::{CommandType::*, Error::SubscriptionFailed, *};
4use async_io::{Async, Timer};
5use futures_lite::AsyncWriteExt;
6use serde::de::DeserializeOwned as Deserialize;
7use std::io::ErrorKind::NotConnected;
8use std::os::unix::net::UnixStream;
9use std::time::Duration;
10
11const MAX_CONNECT_RETRIES: u8 = u8::MAX;
12
13#[derive(Debug)]
14pub struct Connection(Async<UnixStream>);
15
16impl Connection {
17    /// Creates a new async `Connection` to sway-ipc.
18    pub async fn new() -> Fallible<Self> {
19        let socketpath = get_socketpath().await?;
20        let mut retries = 0;
21        loop {
22            let connection = Async::<UnixStream>::connect(socketpath.as_path())
23                .await
24                .map(Self);
25            if matches!(connection.as_ref().map_err(|e| e.kind()), Err(NotConnected))
26                && retries != MAX_CONNECT_RETRIES
27            {
28                Timer::after(Duration::from_millis(100)).await;
29            } else {
30                return Ok(connection?);
31            }
32            retries += 1;
33        }
34    }
35
36    async fn raw_command<D: Deserialize>(&mut self, command_type: CommandType) -> Fallible<D> {
37        self.0.write_all(command_type.encode().as_slice()).await?;
38        command_type.decode(receive_from_stream(&mut self.0).await?)
39    }
40
41    async fn raw_command_with<D: Deserialize, T: AsRef<[u8]>>(
42        &mut self,
43        command_type: CommandType,
44        payload: T,
45    ) -> Fallible<D> {
46        self.0
47            .write_all(command_type.encode_with(payload).as_slice())
48            .await?;
49        command_type.decode(receive_from_stream(&mut self.0).await?)
50    }
51
52    /// Runs the payload as sway commands.
53    pub async fn run_command<T: AsRef<str>>(&mut self, payload: T) -> Fallible<Vec<Fallible<()>>> {
54        let outcome: Vec<CommandOutcome> =
55            self.raw_command_with(RunCommand, payload.as_ref()).await?;
56        Ok(outcome.into_iter().map(CommandOutcome::decode).collect())
57    }
58
59    /// Get the list of current workspaces.
60    pub async fn get_workspaces(&mut self) -> Fallible<Vec<Workspace>> {
61        self.raw_command(GetWorkspaces).await
62    }
63
64    /// Subscribe the IPC connection to the events listed in the payload.
65    pub async fn subscribe<T: AsRef<[EventType]>>(mut self, events: T) -> Fallible<EventStream> {
66        let events = serde_json::ser::to_string(events.as_ref())?;
67        let res: Success = self.raw_command_with(Subscribe, events.as_bytes()).await?;
68        if !res.success {
69            return Err(SubscriptionFailed(events));
70        }
71        Ok(EventStream::new(self.0))
72    }
73
74    /// Get the list of current outputs.
75    pub async fn get_outputs(&mut self) -> Fallible<Vec<Output>> {
76        self.raw_command(GetOutputs).await
77    }
78
79    /// Get the node layout tree.
80    pub async fn get_tree(&mut self) -> Fallible<Node> {
81        self.raw_command(GetTree).await
82    }
83
84    /// Get the names of all the marks currently set.
85    pub async fn get_marks(&mut self) -> Fallible<Vec<String>> {
86        self.raw_command(GetMarks).await
87    }
88
89    /// Get a list of bar config names.
90    pub async fn get_bar_ids(&mut self) -> Fallible<Vec<String>> {
91        self.raw_command(GetBarConfig).await
92    }
93
94    /// Get the specified bar config.
95    pub async fn get_bar_config<T: AsRef<str>>(&mut self, id: T) -> Fallible<BarConfig> {
96        self.raw_command_with(GetBarConfig, id.as_ref()).await
97    }
98
99    /// Get the version of sway that owns the IPC socket.
100    pub async fn get_version(&mut self) -> Fallible<Version> {
101        self.raw_command(GetVersion).await
102    }
103
104    /// Get the list of binding mode names.
105    pub async fn get_binding_modes(&mut self) -> Fallible<Vec<String>> {
106        self.raw_command(GetBindingModes).await
107    }
108
109    /// Returns the config that was last loaded.
110    pub async fn get_config(&mut self) -> Fallible<Config> {
111        self.raw_command(GetConfig).await
112    }
113
114    /// Sends a tick event with the specified payload.
115    pub async fn send_tick<T: AsRef<str>>(&mut self, payload: T) -> Fallible<bool> {
116        let res: Success = self.raw_command_with(SendTick, payload.as_ref()).await?;
117        Ok(res.success)
118    }
119
120    /// Replies failure object for i3 compatibility.
121    pub async fn sync(&mut self) -> Fallible<bool> {
122        let res: Success = self.raw_command(Sync).await?;
123        Ok(res.success)
124    }
125
126    /// Request the current binding state, e.g.  the currently active binding
127    /// mode name.
128    pub async fn get_binding_state(&mut self) -> Fallible<String> {
129        let state: BindingState = self.raw_command(GetBindingState).await?;
130        Ok(state.name)
131    }
132
133    /// Get the list of input devices.
134    pub async fn get_inputs(&mut self) -> Fallible<Vec<Input>> {
135        self.raw_command(GetInputs).await
136    }
137
138    /// Get the list of seats.
139    pub async fn get_seats(&mut self) -> Fallible<Vec<Seat>> {
140        self.raw_command(GetSeats).await
141    }
142}
143
144impl From<Async<UnixStream>> for Connection {
145    fn from(unix_stream: Async<UnixStream>) -> Self {
146        Self(unix_stream)
147    }
148}
149
150impl From<Connection> for Async<UnixStream> {
151    fn from(connection: Connection) -> Self {
152        connection.0
153    }
154}