use irelia_encoder::Encoder;
use std::path::Path;
use sysinfo::{ProcessRefreshKind, RefreshKind, System};
use crate::Error;
const CLIENT_PROCESS_NAME: &str = "CrBrowserMain";
const GAME_PROCESS_NAME: &str = "CrBrowserMain";
pub(crate) const ENCODER: Encoder = Encoder::new();
pub fn get_running_client(force_lock_file: bool) -> Result<(String, String), Error> {
let cmd = if force_lock_file {
sysinfo::UpdateKind::Never
} else {
sysinfo::UpdateKind::OnlyIfNotSet
};
let refresh_kind = ProcessRefreshKind::new()
.with_exe(sysinfo::UpdateKind::OnlyIfNotSet)
.with_cmd(cmd);
let system = System::new_with_specifics(
RefreshKind::new().with_processes(refresh_kind),
);
let mut client = false;
let process = system
.processes()
.values()
.find(|process| {
let name = process.name();
if name == CLIENT_PROCESS_NAME {
client = true;
client
} else {
name == GAME_PROCESS_NAME
}
})
.ok_or_else(|| Error::LCUProcessNotRunning)?;
let mut lock_file: String = String::new();
let port: &str;
let auth: &str;
if client {
if force_lock_file {
let path = process.exe().ok_or_else(|| Error::LockFileNotFound)?;
let path = path.parent().ok_or_else(|| Error::LockFileNotFound)?;
(port, auth) = read_and_parse_lock(path, &mut lock_file)?;
} else {
let cmd = process.cmd();
let mut iter = cmd.iter();
auth = iter
.find_map(|s| s.strip_prefix("--remoting-auth-token="))
.ok_or(Error::AuthTokenNotFound)?;
port = iter
.find_map(|s| s.strip_prefix("--app-port="))
.ok_or(Error::PortNotFound)?;
}
} else {
let path = process.exe().ok_or_else(|| Error::LockFileNotFound)?;
let path = path
.parent()
.ok_or_else(|| Error::LockFileNotFound)?
.parent()
.ok_or_else(|| Error::LockFileNotFound)?;
(port, auth) = read_and_parse_lock(path, &mut lock_file)?;
}
let auth_header = ENCODER.encode(format!("riot:{auth}"));
Ok((
format!("127.0.0.1:{port}"),
format!("Basic {auth_header}", ),
))
}
fn read_and_parse_lock<'a>(
path: &Path,
lock_file: &'a mut String,
) -> Result<(&'a str, &'a str), Error> {
*lock_file = std::fs::read_to_string(path.join("lockfile")).map_err(Error::StdIo)?;
let mut split = lock_file.split(':');
let port = split.nth(2).ok_or(Error::PortNotFound)?;
let auth = split.next().ok_or(Error::AuthTokenNotFound)?;
Ok((port, auth))
}
#[cfg(test)]
mod tests {
use super::get_running_client;
#[ignore = "This is only needed for testing, and doesn't need to be run all the time"]
#[test]
fn test_process_info() {
let (port, pass) = get_running_client(false).unwrap();
println!("{port} {pass}");
}
}