1
2use crate::errors::{JavaRuntimeError, JavaRuntimeResult};
3use std::path::{Path, PathBuf};
4use std::process::Stdio;
5use tracing::info;
6use tokio::io::AsyncReadExt;
7use tokio::process::{Child, Command};
8use tokio::sync::oneshot::Receiver;
9use tracing::debug;
10pub struct JavaRuntime(pub PathBuf);
11
12impl JavaRuntime {
13 pub fn new(path: PathBuf) -> JavaRuntime {
14 JavaRuntime(path)
15 }
16
17 pub async fn execute(&self, arguments: Vec<String>, game_dir: &Path) -> JavaRuntimeResult<Child> {
18 if !self.0.exists() {
19 return Err(JavaRuntimeError::NotFound {
20 path: self.0.display().to_string(),
21 });
22 }
23 let mut command = Command::new(&self.0);
24
25
26 debug!("Executing Java runtime: {}", self.0.display());
28 info!("Executing Java runtime: {}", self.0.display());
29 info!("Arguments: {:?}", &arguments);
30
31
32
33
34 command.current_dir(game_dir);
35
36 command.args(arguments);
37 println!("Java runtime: {}", self.0.display());
38
39 command.stderr(Stdio::piped()).stdout(Stdio::piped());
40
41 let child = command.spawn()?;
42 Ok(child)
43 }
44
45 pub async fn handle_io<D: Send + Sync>(
46 &self,
47 running_task: &mut Child,
48 on_stdout: fn(&D, &[u8]) -> JavaRuntimeResult<()>,
49 on_stderr: fn(&D, &[u8]) -> JavaRuntimeResult<()>,
50 terminator: Receiver<()>,
51 data: &D,
52 ) -> JavaRuntimeResult<()> {
53 let mut stdout = running_task.stdout.take()
54 .ok_or(JavaRuntimeError::IoCaptureFailure)?;
55 let mut stderr = running_task.stderr.take()
56 .ok_or(JavaRuntimeError::IoCaptureFailure)?;
57
58 let mut stdout_buf = vec![0; 1024];
59 let mut stderr_buf = vec![0; 1024];
60
61 tokio::pin!(terminator);
62
63 loop {
64 tokio::select! {
65 read_len = stdout.read(&mut stdout_buf) => {
66 let _ = on_stdout(&data, &stdout_buf[..read_len?]);
67 },
68 read_len = stderr.read(&mut stderr_buf) => {
69 let _ = on_stderr(&data, &stderr_buf[..read_len?]);
70 },
71 _ = &mut terminator => {
72 running_task.kill().await?;
73 break;
74 },
75 exit_status = running_task.wait() => {
76 let code = exit_status?.code().unwrap_or(7900); debug!("Process exited with code: {}", code);
79 if code != 0 && code != -1073740791 { return Err(JavaRuntimeError::NonZeroExit { code });
81 }
82 break;
83 },
84 }
85 }
86 Ok(())
87 }
88}