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