use crate::errors::{JavaRuntimeError, JavaRuntimeResult};
use std::path::{Path, PathBuf};
use std::process::Stdio;
use tokio::io::AsyncReadExt;
use tokio::process::{Child, Command};
use tokio::sync::oneshot::Receiver;
pub struct JavaRuntime(pub PathBuf);
impl JavaRuntime {
pub fn new(path: PathBuf) -> Self {
Self(path)
}
pub async fn execute(&self, arguments: Vec<String>, game_dir: &Path) -> JavaRuntimeResult<Child> {
if !self.0.exists() {
return Err(JavaRuntimeError::NotFound {
path: self.0.clone(),
});
}
lighty_core::trace_debug!("Spawning Java process: {:?}", &self.0);
lighty_core::trace_info!("Java arguments: {:?}", &arguments);
let child = Command::new(&self.0)
.current_dir(game_dir)
.args(arguments)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()?;
lighty_core::trace_info!("Java process spawned successfully");
Ok(child)
}
pub async fn handle_io<D: Send + Sync>(
&self,
process: &mut Child,
on_stdout: fn(&D, &[u8]) -> JavaRuntimeResult<()>,
on_stderr: fn(&D, &[u8]) -> JavaRuntimeResult<()>,
terminator: Receiver<()>,
data: &D,
) -> JavaRuntimeResult<()> {
let mut stdout = process
.stdout
.take()
.ok_or(JavaRuntimeError::IoCaptureFailure)?;
let mut stderr = process
.stderr
.take()
.ok_or(JavaRuntimeError::IoCaptureFailure)?;
let mut stdout_buffer = [0u8; 8192];
let mut stderr_buffer = [0u8; 8192];
tokio::pin!(terminator);
loop {
tokio::select! {
result = stdout.read(&mut stdout_buffer) => {
match result {
Ok(bytes_read) if bytes_read > 0 => {
let _ = on_stdout(data, &stdout_buffer[..bytes_read]);
}
Ok(_) => {}, Err(_) => break, }
},
result = stderr.read(&mut stderr_buffer) => {
match result {
Ok(bytes_read) if bytes_read > 0 => {
let _ = on_stderr(data, &stderr_buffer[..bytes_read]);
}
Ok(_) => {}, Err(_) => break, }
},
_ = &mut terminator => {
lighty_core::trace_debug!("Termination signal received, killing process");
process.kill().await?;
break;
},
exit_result = process.wait() => {
let exit_status = exit_result?;
let exit_code = exit_status.code().unwrap_or(7900);
lighty_core::trace_debug!("Java process exited with code: {}", exit_code);
if exit_code != 0 && exit_code != -1073740791 {
return Err(JavaRuntimeError::NonZeroExit { code: exit_code });
}
break;
},
}
}
Ok(())
}
}