1use anyhow::Error;
2use std::{io::BufRead, process::Command, thread};
3use tokio::sync::mpsc::UnboundedSender;
4
5pub fn start_code_tunnel(sender: UnboundedSender<String>, dir: &str) -> Result<u32, Error> {
6 verify_if_code_is_installed()?;
7
8 let mut child = Command::new("code")
9 .arg("tunnel")
10 .arg("--accept-server-license-terms")
11 .current_dir(dir)
12 .stdout(std::process::Stdio::piped())
13 .stderr(std::process::Stdio::piped())
14 .spawn()
15 .expect("failed to execute process");
16
17 let pid = child.id();
18
19 thread::spawn(move || {
20 let stdout = child.stdout.take().expect("Failed to get stdout handle");
21 let stderr = child.stderr.take().expect("Failed to get stderr handle");
22 let stdout_reader = std::io::BufReader::new(stdout);
23 let stderr_reader = std::io::BufReader::new(stderr);
24
25 for line in stdout_reader.lines() {
26 if let Ok(line) = line {
27 sender.send(line).unwrap();
28 }
29 }
30
31 for line in stderr_reader.lines() {
32 if let Ok(line) = line {
33 sender.send(line).unwrap();
34 }
35 }
36
37 drop(sender);
38
39 child.wait().expect("Failed to wait on child");
40 });
41
42 Ok(pid)
43}
44
45fn verify_if_code_is_installed() -> Result<(), Error> {
46 let output = Command::new("code")
47 .arg("--version")
48 .output()
49 .expect("failed to execute process");
50
51 if !output.status.success() {
52 return Err(Error::msg("Code is not installed"));
53 }
54
55 Ok(())
56}