use super::GameProcess;
use crate::error::LaunchResult;
use async_trait::async_trait;
use parking_lot::Mutex;
use std::os::windows::process::CommandExt;
use std::process::Child;
use std::process::Command;
use std::sync::Arc;
use std::thread::sleep;
use std::time::Duration;
use tokio::task;
#[cfg_attr(doc_cfg, doc(cfg(windows)))]
#[derive(Clone, Debug)]
pub struct GameProcessHandle {
child: Arc<Mutex<Child>>,
}
#[async_trait]
impl GameProcess for GameProcessHandle {
fn launch(mut command: Command) -> LaunchResult<Self> {
command.creation_flags(0x00000200 | 0x00000008);
let child = command.spawn()?;
Ok(Self {
child: Arc::new(Mutex::new(child)),
})
}
async fn stop(&self) -> LaunchResult<()> {
let child = self.child.clone();
task::spawn_blocking(move || {
let mut child = child.lock();
child.kill()?;
Ok(())
})
.await
.unwrap()
}
async fn wait(&self) -> LaunchResult<()> {
let handle = Self {
child: self.child.clone(),
};
task::spawn_blocking(move || {
loop {
if handle.is_stopped_blocking()? {
break;
}
sleep(Duration::from_millis(500));
}
let mut child = handle.child.lock();
child.wait()?;
Ok(())
})
.await
.unwrap()
}
async fn is_stopped(&self) -> LaunchResult<bool> {
let child = self.child.clone();
task::spawn_blocking(move || {
let mut child = child.lock();
match child.try_wait()? {
Some(_) => Ok(true),
None => Ok(false),
}
})
.await
.unwrap()
}
fn is_stopped_blocking(&self) -> LaunchResult<bool> {
let mut child = self.child.lock();
match child.try_wait()? {
Some(_) => Ok(true),
None => Ok(false),
}
}
}