use std::env;
use std::fs;
use std::path::PathBuf;
use std::process::ExitCode;
#[tokio::main(flavor = "current_thread")]
async fn main() -> ExitCode {
let args: Vec<String> = env::args().collect();
if let Ok(log_path) = env::var("FAKE_CHROME_ARGS_LOG") {
let _ = fs::write(&log_path, args.join("\n"));
}
let mode = env::var("FAKE_CHROME_MODE").unwrap_or_else(|_| "serve".to_string());
match mode.as_str() {
"exit_immediately" => ExitCode::from(1),
"hang_no_port" => loop {
tokio::time::sleep(std::time::Duration::from_secs(3600)).await;
},
"ignore_sigterm" => serve(args, true).await,
"serve" => serve(args, false).await,
_ => ExitCode::from(2),
}
}
fn parse_args(args: &[String]) -> (u16, Option<PathBuf>) {
let mut port: u16 = 0;
let mut user_data_dir: Option<PathBuf> = None;
let mut iter = args.iter();
while let Some(arg) = iter.next() {
if let Some(v) = arg.strip_prefix("--remote-debugging-port=") {
port = v.parse().unwrap_or(0);
} else if arg == "--remote-debugging-port" {
if let Some(next) = iter.next() {
port = next.parse().unwrap_or(0);
}
} else if let Some(v) = arg.strip_prefix("--user-data-dir=") {
user_data_dir = Some(PathBuf::from(v));
} else if arg == "--user-data-dir"
&& let Some(next) = iter.next()
{
user_data_dir = Some(PathBuf::from(next));
}
}
(port, user_data_dir)
}
async fn serve(args: Vec<String>, ignore_sigterm: bool) -> ExitCode {
let (port, user_data_dir) = parse_args(&args);
let bind = format!("127.0.0.1:{port}");
let listener = match tokio::net::TcpListener::bind(&bind).await {
Ok(l) => l,
Err(_) => return ExitCode::from(2),
};
let actual_port = match listener.local_addr() {
Ok(a) => a.port(),
Err(_) => return ExitCode::from(3),
};
if let Some(dir) = user_data_dir {
let _ = fs::create_dir_all(&dir);
let file = dir.join("DevToolsActivePort");
let _ = fs::write(&file, format!("{actual_port}\n"));
}
if ignore_sigterm {
#[cfg(unix)]
{
let mut sigterm =
match tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate()) {
Ok(s) => s,
Err(_) => return ExitCode::from(4),
};
loop {
tokio::select! {
biased;
_ = sigterm.recv() => {
}
accept_res = listener.accept() => {
if accept_res.is_err() {
return ExitCode::from(5);
}
}
}
}
}
#[cfg(not(unix))]
{
let _ = ignore_sigterm;
loop {
if listener.accept().await.is_err() {
return ExitCode::from(5);
}
}
}
} else {
loop {
if listener.accept().await.is_err() {
return ExitCode::from(5);
}
}
}
}