term_session/
auto_spawn.rs1use std::io;
2use std::process::{Child, Command, Stdio};
3use std::thread;
4use std::time::{Duration, Instant};
5
6use term_session_muxio_service_definitions::{ChannelName, probe_ipc_endpoint};
7
8#[derive(Clone, Debug)]
10pub struct ServerSpawnConfig<'a> {
11 pub channel: &'a ChannelName,
12 pub cols: u16,
13 pub rows: u16,
14 pub cmd: &'a [String],
15}
16
17fn spawn_detached_server(cfg: &ServerSpawnConfig<'_>) -> io::Result<Child> {
18 let bin = std::env::current_exe()?;
19 let mut cmd = Command::new(bin);
20 cmd.arg("--server")
21 .arg("--channel")
22 .arg(cfg.channel.to_string());
23 cmd.arg("--cols").arg(cfg.cols.to_string());
24 cmd.arg("--rows").arg(cfg.rows.to_string());
25 if !cfg.cmd.is_empty() {
26 cmd.arg("--").args(cfg.cmd);
27 }
28 cmd.stdin(Stdio::null())
33 .stdout(Stdio::null())
34 .stderr(Stdio::null());
35 #[cfg(unix)]
36 {
37 use std::os::unix::process::CommandExt;
38 unsafe {
45 cmd.pre_exec(|| {
46 if libc::setsid() == -1 {
47 return Err(std::io::Error::last_os_error());
48 }
49 Ok(())
50 });
51 }
52 }
53 #[cfg(windows)]
54 {
55 use std::os::windows::process::CommandExt;
56 cmd.creation_flags(0x08000000);
57 }
58 cmd.spawn()
59}
60
61pub fn connect_or_spawn_server(
68 channel: &ChannelName,
69 cfg: &ServerSpawnConfig<'_>,
70) -> io::Result<String> {
71 let socket_name = channel.to_string();
72
73 if probe_ipc_endpoint(channel) {
74 return Ok(socket_name);
75 }
76
77 let mut child = spawn_detached_server(cfg)?;
78 let start = Instant::now();
79 let timeout = Duration::from_secs(3);
80 let poll_interval = Duration::from_millis(50);
81
82 while start.elapsed() < timeout {
83 if probe_ipc_endpoint(channel) {
84 return Ok(socket_name);
85 }
86 if let Ok(Some(status)) = child.try_wait() {
87 if probe_ipc_endpoint(channel) {
90 return Ok(socket_name);
91 }
92 return Err(io::Error::new(
93 io::ErrorKind::ConnectionRefused,
94 format!("Session server exited during startup with status: {status}"),
95 ));
96 }
97 thread::sleep(poll_interval);
98 }
99
100 Err(io::Error::new(
101 io::ErrorKind::TimedOut,
102 format!("Timed out waiting for server on channel '{channel}'"),
103 ))
104}