hyprshell_hyprland/
instance.rs1use crate::error::hypr_err;
2use crate::shared::{CommandContent, get_hypr_path};
3use std::path::{Path, PathBuf};
4
5#[derive(Debug, Clone)]
8pub struct Instance {
9 instance: String,
10 stream: Box<Path>,
12 #[cfg(feature = "hyprpaper")]
14 hyprpaper_stream: Box<Path>,
15 #[cfg(feature = "listener")]
17 event_socket_path: Box<Path>,
18}
19
20impl PartialEq<Self> for Instance {
21 fn eq(&self, other: &Self) -> bool {
22 self.instance == other.instance
23 }
24}
25
26impl Instance {
27 pub fn from_current_env() -> crate::Result<Self> {
29 let mut path = get_hypr_path()?;
30 let name = get_env_name()?;
31 path.push(&name);
32 Self::from_base_socket_path(path)
33 }
34
35 pub fn from_instance(name: String) -> crate::Result<Self> {
39 let mut path = get_hypr_path()?;
40 path.push(&name);
41 Self::from_base_socket_path(path)
42 }
43
44 pub fn from_base_socket_path(path: PathBuf) -> crate::Result<Self> {
48 let Some(name) = path.file_name().map(|n| n.to_string_lossy().to_string()) else {
49 hypr_err!("Could not get instance name from path: {}", path.display());
50 };
51 if !path.exists() {
52 hypr_err!("Hyprland instance path does not exist: {}", path.display());
53 }
54 Ok(Self {
55 instance: name,
56 stream: path.join(".socket.sock").into_boxed_path(),
57 #[cfg(feature = "listener")]
58 event_socket_path: path.join(".socket2.sock").into_boxed_path(),
59 #[cfg(feature = "hyprpaper")]
60 hyprpaper_stream: path.join(".hyprpaper.sock").into_boxed_path(),
61 })
62 }
63}
64
65impl Instance {
66 pub(crate) fn write_to_socket(&self, content: CommandContent) -> crate::Result<String> {
67 use std::io::{Read, Write};
68 let mut stream = std::os::unix::net::UnixStream::connect(&self.stream)?;
69 #[cfg(feature = "trace")]
70 tracing::trace!("Sending command: {}", content.data);
71 stream.write_all(&content.as_bytes())?;
72 let mut response = Vec::new();
73 stream.read_to_end(&mut response)?;
74 Ok(String::from_utf8_lossy(&response).to_string())
75 }
76
77 #[cfg(any(feature = "async-lite", feature = "tokio"))]
78 pub(crate) async fn write_to_socket_async(
79 &self,
80 content: CommandContent,
81 ) -> crate::Result<String> {
82 use crate::async_import::{AsyncReadExt, AsyncWriteExt};
83 let mut stream = crate::async_import::UnixStream::connect(&self.stream).await?;
84 #[cfg(feature = "trace")]
85 tracing::trace!("Sending command: {}", content.data);
86 stream.write_all(&content.as_bytes()).await?;
87 let mut response = Vec::new();
88 stream.read_to_end(&mut response).await?;
89 Ok(String::from_utf8_lossy(&response).to_string())
90 }
91
92 #[cfg(feature = "hyprpaper")]
93 pub(crate) fn write_to_hyprpaper_socket(
94 &self,
95 content: CommandContent,
96 ) -> crate::Result<String> {
97 use std::io::{Read, Write};
98 let mut stream = std::os::unix::net::UnixStream::connect(&self.hyprpaper_stream)?;
99 #[cfg(feature = "trace")]
100 tracing::trace!("Sending command: {}", content.data);
101 stream.write_all(content.data.as_bytes())?;
102
103 let mut response = Vec::new();
104 const BUFFER_SIZE: usize = 4096;
105 let mut buf = [0u8; BUFFER_SIZE];
106 loop {
107 let n = stream.read(&mut buf[..])?;
108 response.extend_from_slice(&buf[..n]);
109 if n < BUFFER_SIZE {
110 break;
111 }
112 }
113 Ok(String::from_utf8_lossy(&response).to_string())
114 }
115
116 #[cfg(all(feature = "hyprpaper", any(feature = "async-lite", feature = "tokio")))]
117 pub(crate) async fn write_to_hyprpaper_socket_async(
118 &self,
119 content: CommandContent,
120 ) -> crate::Result<String> {
121 use crate::async_import::{AsyncReadExt, AsyncWriteExt};
122 let mut stream = crate::async_import::UnixStream::connect(&self.hyprpaper_stream).await?;
123 #[cfg(feature = "trace")]
124 tracing::trace!("Sending command: {}", content.data);
125 stream.write_all(content.data.as_bytes()).await?;
126
127 let mut response = Vec::new();
128 const BUFFER_SIZE: usize = 4096;
129 let mut buf = [0u8; BUFFER_SIZE];
130 loop {
131 let n = stream.read(&mut buf[..]).await?;
132 response.extend_from_slice(&buf[..n]);
133 if n < BUFFER_SIZE {
134 break;
135 }
136 }
137 Ok(String::from_utf8_lossy(&response).to_string())
138 }
139
140 #[cfg(feature = "listener")]
141 pub(crate) fn get_event_stream(&self) -> crate::Result<std::os::unix::net::UnixStream> {
142 let stream = std::os::unix::net::UnixStream::connect(&self.event_socket_path)?;
143 Ok(stream)
144 }
145
146 #[cfg(all(feature = "listener", any(feature = "async-lite", feature = "tokio")))]
147 pub(crate) async fn get_event_stream_async(
148 &self,
149 ) -> crate::Result<crate::async_import::UnixStream> {
150 let stream = crate::async_import::UnixStream::connect(&self.event_socket_path).await?;
151 Ok(stream)
152 }
153}
154
155fn get_env_name() -> crate::Result<String> {
156 let instance = match std::env::var("HYPRLAND_INSTANCE_SIGNATURE") {
157 Ok(var) => var,
158 Err(std::env::VarError::NotPresent) => {
159 hypr_err!("Could not get socket path! (Is Hyprland running??)")
160 }
161 Err(std::env::VarError::NotUnicode(_)) => {
162 hypr_err!("Corrupted Hyprland socket variable: Invalid unicode!")
163 }
164 };
165 Ok(instance)
166}