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
121
122
123
124
125
126
127
128
129
use super::common::receive_from_stream;
use super::socket::get_socket_path;
use crate::{CommandType::*, Error::SubscriptionFailed, *};
use async_io::{Async, Timer};
use futures_lite::AsyncWriteExt;
use serde::de::DeserializeOwned as Deserialize;
use std::io::ErrorKind::NotConnected;
use std::os::unix::net::UnixStream;
use std::time::Duration;

#[derive(Debug)]
pub struct Connection(Async<UnixStream>);

impl Connection {
    pub async fn new() -> Fallible<Self> {
        let socket_path = get_socket_path().await?;
        loop {
            let stream = Async::<UnixStream>::connect(&socket_path).await;
            if let Err(NotConnected) = stream.as_ref().map_err(|e| e.kind()) {
                Timer::after(Duration::from_millis(100)).await;
            } else {
                return Ok(Self(stream?));
            }
        }
    }

    async fn raw_command<D: Deserialize>(&mut self, command_type: CommandType) -> Fallible<D> {
        self.0.write_all(&command_type.encode()).await?;
        command_type.decode(receive_from_stream(&mut self.0).await?)
    }

    async fn raw_command_with<D: Deserialize>(
        &mut self,
        command_type: CommandType,
        payload: &str,
    ) -> Fallible<D> {
        self.0.write_all(&command_type.encode_with(payload)).await?;
        command_type.decode(receive_from_stream(&mut self.0).await?)
    }

    pub async fn run_command<T: AsRef<str>>(&mut self, payload: T) -> Fallible<Vec<Fallible<()>>> {
        let outcome: Vec<CommandOutcome> =
            self.raw_command_with(RunCommand, payload.as_ref()).await?;
        Ok(outcome.into_iter().map(CommandOutcome::decode).collect())
    }

    pub async fn get_workspaces(&mut self) -> Fallible<Vec<Workspace>> {
        self.raw_command(GetWorkspaces).await
    }

    pub async fn subscribe(mut self, events: &[EventType]) -> Fallible<EventStream> {
        let events = serde_json::ser::to_string(events)?;
        if !self
            .raw_command_with::<Success>(Subscribe, &events)
            .await?
            .success
        {
            return Err(SubscriptionFailed(events));
        }
        Ok(EventStream::new(self.0))
    }

    pub async fn get_outputs(&mut self) -> Fallible<Vec<Output>> {
        self.raw_command(GetOutputs).await
    }

    pub async fn get_tree(&mut self) -> Fallible<Node> {
        self.raw_command(GetTree).await
    }

    pub async fn get_marks(&mut self) -> Fallible<Vec<String>> {
        self.raw_command(GetMarks).await
    }

    pub async fn get_bar_ids(&mut self) -> Fallible<Vec<String>> {
        self.raw_command(GetBarConfig).await
    }

    pub async fn get_bar_config<T: AsRef<str>>(&mut self, id: T) -> Fallible<BarConfig> {
        self.raw_command_with(GetBarConfig, id.as_ref()).await
    }

    pub async fn get_version(&mut self) -> Fallible<Version> {
        self.raw_command(GetVersion).await
    }

    pub async fn get_binding_modes(&mut self) -> Fallible<Vec<String>> {
        self.raw_command(GetBindingModes).await
    }

    pub async fn get_config(&mut self) -> Fallible<Config> {
        self.raw_command(GetConfig).await
    }

    pub async fn send_tick<T: AsRef<str>>(&mut self, payload: T) -> Fallible<bool> {
        let res: Success = self.raw_command_with(SendTick, payload.as_ref()).await?;
        Ok(res.success)
    }

    pub async fn sync(&mut self) -> Fallible<bool> {
        let res: Success = self.raw_command(Sync).await?;
        Ok(res.success)
    }

    pub async fn get_binding_state(&mut self) -> Fallible<String> {
        let state: BindingState = self.raw_command(GetBindingState).await?;
        Ok(state.name)
    }

    pub async fn get_inputs(&mut self) -> Fallible<Vec<Input>> {
        self.raw_command(GetInputs).await
    }

    pub async fn get_seats(&mut self) -> Fallible<Vec<Seat>> {
        self.raw_command(GetSeats).await
    }
}

impl From<Async<UnixStream>> for Connection {
    fn from(unix_stream: Async<UnixStream>) -> Self {
        Self(unix_stream)
    }
}

impl From<Connection> for Async<UnixStream> {
    fn from(connection: Connection) -> Self {
        connection.0
    }
}