1use {
4 crate::{
5 acceptor::{Acceptor, AcceptorError},
6 baseline::Baseline,
7 client::ClientHandler,
8 protocols::wayland::wl_display::WlDisplayHandler,
9 state::{Destructor, State},
10 utils::env::WAYLAND_DISPLAY,
11 },
12 error_reporter::Report,
13 parking_lot::Mutex,
14 run_on_drop::on_drop,
15 std::{
16 io,
17 os::unix::prelude::ExitStatusExt,
18 process::{Command, exit},
19 rc::Rc,
20 sync::atomic::{AtomicUsize, Ordering::Relaxed},
21 thread,
22 },
23 thiserror::Error,
24 uapi::raise,
25};
26
27pub struct SimpleProxy {
32 baseline: Baseline,
33 acceptor: Rc<Acceptor>,
34}
35
36#[derive(Debug, Error)]
38#[error(transparent)]
39pub struct SimpleProxyError(#[from] SimpleProxyErrorKind);
40
41#[derive(Debug, Error)]
42enum SimpleProxyErrorKind {
43 #[error("could not create an acceptor")]
44 CreateAcceptor(#[source] AcceptorError),
45 #[error("could not accept a connection")]
46 AcceptConnection(#[source] AcceptorError),
47 #[error("could not spawn a thread")]
48 SpawnThread(#[source] io::Error),
49}
50
51impl SimpleProxy {
52 pub fn new(baseline: Baseline) -> Result<SimpleProxy, SimpleProxyError> {
54 Ok(Self {
55 baseline,
56 acceptor: Acceptor::new(1000, false).map_err(SimpleProxyErrorKind::CreateAcceptor)?,
57 })
58 }
59
60 pub fn display(&self) -> &str {
65 self.acceptor.display()
66 }
67
68 pub fn run<H>(self, display_handler: impl Fn() -> H + Sync) -> SimpleProxyError
72 where
73 H: WlDisplayHandler,
74 {
75 static ID: AtomicUsize = AtomicUsize::new(1);
76 let display_handler = &display_handler;
77 let destructors = Mutex::new(Some(vec![]));
78 let destructors = &destructors;
79 let err = thread::scope(|s| {
80 let _stop_all_proxies = on_drop(|| *destructors.lock() = None);
81 loop {
82 let socket = match self.acceptor.accept() {
83 Ok(s) => s.expect("blocking acceptor returned None"),
84 Err(e) => return SimpleProxyErrorKind::AcceptConnection(e),
85 };
86 let id = ID.fetch_add(1, Relaxed);
87 let name = format!("socket-{id}");
88 log::debug!("Client {id} connected");
89 let res = thread::Builder::new()
90 .name(name.clone())
91 .spawn_scoped(s, move || {
92 let state = State::builder(self.baseline).with_log_prefix(&name).build();
93 let state = match state {
94 Ok(s) => s,
95 Err(e) => {
96 log::error!("Could not create a new state: {}", Report::new(e));
97 return;
98 }
99 };
100 match state.create_remote_destructor() {
101 Ok(d) => match &mut *destructors.lock() {
102 Some(des) => des.push(d),
103 _ => return,
104 },
105 Err(e) => {
106 log::error!(
107 "Could not create a remote destructor: {}",
108 Report::new(e),
109 );
110 return;
111 }
112 }
113 let client = match state.add_client(&Rc::new(socket)) {
114 Ok(c) => c,
115 Err(e) => {
116 log::error!("Could not add client to state: {}", Report::new(e));
117 return;
118 }
119 };
120 client.set_handler(ClientHandlerImpl {
121 id,
122 _destructor: state.create_destructor(),
123 });
124 let handler = display_handler();
125 client.display().set_handler(handler);
126 while state.is_not_destroyed() {
127 if let Err(e) = state.dispatch_blocking() {
128 log::error!("Could not dispatch state: {}", Report::new(e));
129 }
130 }
131 });
132 if let Err(e) = res {
133 return SimpleProxyErrorKind::SpawnThread(e);
134 }
135 }
136 });
137 SimpleProxyError(err)
138 }
139}
140
141struct ClientHandlerImpl {
142 id: usize,
143 _destructor: Destructor,
144}
145
146impl ClientHandler for ClientHandlerImpl {
147 fn disconnected(self: Box<Self>) {
148 log::debug!("Client {} disconnected", self.id);
149 }
150}
151
152pub trait SimpleCommandExt {
154 fn with_wayland_display(&mut self, display: &str) -> &mut Command;
156 fn spawn_and_forward_exit_code(&mut self) -> Result<(), io::Error>;
159}
160
161impl SimpleCommandExt for Command {
162 fn with_wayland_display(&mut self, display: &str) -> &mut Command {
163 self.env(WAYLAND_DISPLAY, display)
164 }
165
166 fn spawn_and_forward_exit_code(&mut self) -> Result<(), io::Error> {
167 let mut child = self.spawn()?;
168 thread::spawn(move || match child.wait() {
169 Ok(e) => {
170 if let Some(code) = e.code() {
171 exit(code);
172 }
173 if let Some(signal) = e.signal() {
174 let _ = raise(signal);
175 exit(1);
176 }
177 eprintln!("Child terminated with neither a signal nor an exit code");
178 exit(1);
179 }
180 Err(e) => {
181 eprintln!("Could not wait for child: {}", Report::new(e));
182 exit(1);
183 }
184 });
185 Ok(())
186 }
187}