1use std::{
7 env, io,
8 os::unix::{
9 io::{AsFd, AsRawFd, BorrowedFd, RawFd},
10 net::{UnixListener, UnixStream},
11 },
12 path::{Path, PathBuf},
13};
14
15use crate::{util, wire::Backend, PendingRequestResult};
16
17pub use crate::eiproto_eis::*;
19
20#[derive(Debug)]
21pub struct Listener {
22 listener: util::UnlinkOnDrop<UnixListener>,
23 _lock: Option<util::LockFile>,
24}
25
26impl Listener {
27 pub fn bind(path: &Path) -> io::Result<Self> {
29 Self::bind_inner(PathBuf::from(path), None)
30 }
31
32 pub fn bind_auto() -> io::Result<Option<Self>> {
35 let xdg_dir = if let Some(var) = env::var_os("XDG_RUNTIME_DIR") {
36 PathBuf::from(var)
37 } else {
38 return Ok(None);
39 };
40 for i in 1..33 {
41 let lock_path = xdg_dir.join(format!("eis-{i}.lock"));
42 let Some(lock_file) = util::LockFile::new(lock_path)? else {
43 continue;
45 };
46 let sock_path = xdg_dir.join(format!("eis-{i}"));
47 return Self::bind_inner(sock_path, Some(lock_file)).map(Some);
48 }
49 Ok(None)
50 }
51
52 fn bind_inner(path: PathBuf, lock: Option<util::LockFile>) -> io::Result<Self> {
53 let listener = UnixListener::bind(&path)?;
54 listener.set_nonblocking(true)?;
55 let listener = util::UnlinkOnDrop::new(listener, path);
56 Ok(Self {
57 listener,
58 _lock: lock,
59 })
60 }
61
62 pub fn accept(&self) -> io::Result<Option<Context>> {
63 match self.listener.accept() {
64 Ok((socket, _)) => Ok(Some(Context::new(socket)?)),
65 Err(e) if e.kind() == io::ErrorKind::WouldBlock => Ok(None),
66 Err(e) => Err(e),
67 }
68 }
69}
70
71impl AsFd for Listener {
72 fn as_fd(&self) -> BorrowedFd {
73 self.listener.as_fd()
74 }
75}
76
77impl AsRawFd for Listener {
78 fn as_raw_fd(&self) -> RawFd {
79 self.listener.as_raw_fd()
80 }
81}
82
83#[derive(Clone, Debug)]
84pub struct Context(pub(crate) Backend);
85
86impl AsFd for Context {
87 fn as_fd(&self) -> BorrowedFd {
88 self.0.as_fd()
89 }
90}
91
92impl AsRawFd for Context {
93 fn as_raw_fd(&self) -> RawFd {
94 self.0.as_fd().as_raw_fd()
95 }
96}
97
98impl Context {
99 pub fn new(socket: UnixStream) -> io::Result<Self> {
100 Ok(Self(Backend::new(socket, false)?))
101 }
102
103 pub fn read(&self) -> io::Result<usize> {
105 self.0.read()
106 }
107
108 pub fn pending_request(&self) -> Option<PendingRequestResult<Request>> {
110 self.0.pending(Request::parse)
111 }
112
113 pub fn handshake(&self) -> handshake::Handshake {
114 self.0.object_for_id(0).unwrap().downcast_unchecked()
115 }
116
117 pub fn flush(&self) -> rustix::io::Result<()> {
118 self.0.flush()
119 }
120}
121
122#[doc(hidden)]
123pub trait Interface: crate::wire::Interface {}