mirror of
https://github.com/Drop-OSS/drop-app.git
synced 2025-11-13 16:22:43 +10:00
feat(process manager): launch games with log files
This commit is contained in:
@ -1,22 +1,62 @@
|
||||
use std::{collections::HashMap, sync::LazyLock};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fs::{File, OpenOptions},
|
||||
path::PathBuf,
|
||||
process::{Child, Command},
|
||||
sync::LazyLock,
|
||||
};
|
||||
|
||||
use log::info;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
db::{DatabaseGameStatus, DATA_ROOT_DIR},
|
||||
DB,
|
||||
};
|
||||
|
||||
pub struct ProcessManager {
|
||||
current_platform: Platform,
|
||||
log_output_dir: PathBuf,
|
||||
processes: HashMap<String, Child>,
|
||||
}
|
||||
|
||||
impl ProcessManager {
|
||||
pub fn new() -> Self {
|
||||
let root_dir_lock = DATA_ROOT_DIR.lock().unwrap();
|
||||
let log_output_dir = root_dir_lock.join("logs");
|
||||
drop(root_dir_lock);
|
||||
|
||||
ProcessManager {
|
||||
current_platform: if cfg!(windows) {
|
||||
Platform::Windows
|
||||
} else {
|
||||
Platform::Linux
|
||||
},
|
||||
|
||||
processes: HashMap::new(),
|
||||
log_output_dir,
|
||||
}
|
||||
}
|
||||
|
||||
fn process_command(&self, raw_command: String) -> (String, Vec<String>) {
|
||||
let command_components = raw_command.split(" ").collect::<Vec<&str>>();
|
||||
let root = match self.current_platform {
|
||||
Platform::Windows => command_components[0].to_string(),
|
||||
Platform::Linux => {
|
||||
let mut root = command_components[0].to_string();
|
||||
if !root.starts_with("./") {
|
||||
root = format!("{}{}", "./", root);
|
||||
}
|
||||
root
|
||||
}
|
||||
};
|
||||
let args = command_components[1..]
|
||||
.into_iter()
|
||||
.map(|v| v.to_string())
|
||||
.collect();
|
||||
(root, args)
|
||||
}
|
||||
|
||||
pub fn valid_platform(&self, platform: &Platform) -> Result<bool, String> {
|
||||
let current = &self.current_platform;
|
||||
let valid_platforms = PROCESS_COMPATABILITY_MATRIX
|
||||
@ -25,6 +65,63 @@ impl ProcessManager {
|
||||
|
||||
Ok(valid_platforms.contains(platform))
|
||||
}
|
||||
|
||||
pub fn launch_game(&mut self, game_id: String) -> Result<(), String> {
|
||||
if self.processes.contains_key(&game_id) {
|
||||
return Err("Game or setup is already running.".to_owned());
|
||||
}
|
||||
|
||||
let db_lock = DB.borrow_data().unwrap();
|
||||
let game_status = db_lock
|
||||
.games
|
||||
.games_statuses
|
||||
.get(&game_id)
|
||||
.ok_or("Game not installed")?;
|
||||
|
||||
let DatabaseGameStatus::Installed {
|
||||
version_name,
|
||||
install_dir,
|
||||
} = game_status
|
||||
else {
|
||||
return Err("Game not installed.".to_owned());
|
||||
};
|
||||
|
||||
let game_version = db_lock
|
||||
.games
|
||||
.game_versions
|
||||
.get(&game_id)
|
||||
.ok_or("Invalid game ID".to_owned())?
|
||||
.get(version_name)
|
||||
.ok_or("Invalid version name".to_owned())?;
|
||||
|
||||
let (command, args) = self.process_command(game_version.launch_command.clone());
|
||||
|
||||
info!("launching process {} in {}", command, install_dir);
|
||||
|
||||
let current_time = chrono::offset::Local::now();
|
||||
let log_file = OpenOptions::new()
|
||||
.write(true)
|
||||
.append(true)
|
||||
.read(true)
|
||||
.create(true)
|
||||
.open(self.log_output_dir.join(format!(
|
||||
"{}-{}.log",
|
||||
game_id,
|
||||
current_time.to_rfc3339()
|
||||
)))
|
||||
.map_err(|v| v.to_string())?;
|
||||
|
||||
let launch_process = Command::new(command)
|
||||
.current_dir(install_dir)
|
||||
.stdout(log_file)
|
||||
.args(args)
|
||||
.spawn()
|
||||
.map_err(|v| v.to_string())?;
|
||||
|
||||
self.processes.insert(game_id, launch_process);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, Hash, PartialEq, Serialize, Deserialize, Clone)]
|
||||
|
||||
Reference in New Issue
Block a user