2025-07-27 16:27:11 +03:30
|
|
|
use clap::{value_parser, Arg, Command};
|
2023-11-07 16:36:30 +03:30
|
|
|
pub mod config_models;
|
2025-07-27 16:27:11 +03:30
|
|
|
mod parser;
|
2023-11-09 12:38:26 +03:30
|
|
|
pub mod utils;
|
2025-11-27 17:33:52 +02:00
|
|
|
mod xray_runner;
|
2023-10-24 17:00:00 +03:30
|
|
|
|
2025-11-27 17:33:52 +02:00
|
|
|
#[tokio::main]
|
|
|
|
|
async fn main() {
|
2025-07-27 22:24:57 +03:30
|
|
|
let matches = Command::new("v2parser")
|
2025-08-04 15:41:58 +03:30
|
|
|
.version("0.3.1")
|
2025-07-27 16:27:11 +03:30
|
|
|
.about("Parses V2ray URI and generates JSON config for xray")
|
|
|
|
|
.arg(
|
|
|
|
|
Arg::new("uri")
|
|
|
|
|
.help("V2ray URI to parse")
|
|
|
|
|
.required(true)
|
|
|
|
|
.index(1),
|
|
|
|
|
)
|
|
|
|
|
.arg(
|
|
|
|
|
Arg::new("socksport")
|
|
|
|
|
.long("socksport")
|
2025-07-27 17:28:51 +03:30
|
|
|
.help("Optional SOCKS5 proxy port for inbound")
|
2025-07-27 16:27:11 +03:30
|
|
|
.value_name("PORT")
|
|
|
|
|
.value_parser(value_parser!(u16)),
|
|
|
|
|
)
|
|
|
|
|
.arg(
|
|
|
|
|
Arg::new("httpport")
|
|
|
|
|
.long("httpport")
|
|
|
|
|
.help("Optional HTTP proxy port for inbound")
|
|
|
|
|
.value_name("PORT")
|
|
|
|
|
.value_parser(value_parser!(u16)),
|
|
|
|
|
)
|
|
|
|
|
.arg(
|
2025-07-28 18:09:14 +03:30
|
|
|
Arg::new("get_metadata")
|
|
|
|
|
.long("get-metadata")
|
|
|
|
|
.help("Only print config meta data")
|
2025-07-27 16:27:11 +03:30
|
|
|
.action(clap::ArgAction::SetTrue),
|
|
|
|
|
)
|
2025-11-27 17:33:52 +02:00
|
|
|
.arg(
|
|
|
|
|
Arg::new("run")
|
|
|
|
|
.long("run")
|
|
|
|
|
.help("Run xray-core with the generated config")
|
|
|
|
|
.action(clap::ArgAction::SetTrue),
|
|
|
|
|
)
|
|
|
|
|
.arg(
|
|
|
|
|
Arg::new("xray_binary")
|
|
|
|
|
.long("xray-binary")
|
|
|
|
|
.help("Path to xray-core binary (default: xray from PATH)")
|
|
|
|
|
.value_name("PATH"),
|
|
|
|
|
)
|
2025-07-27 16:27:11 +03:30
|
|
|
.get_matches();
|
|
|
|
|
|
|
|
|
|
let uri = matches.get_one::<String>("uri").unwrap();
|
|
|
|
|
let socksport = matches.get_one::<u16>("socksport").copied();
|
|
|
|
|
let httpport = matches.get_one::<u16>("httpport").copied();
|
2025-07-28 18:09:14 +03:30
|
|
|
let get_metadata = matches.get_flag("get_metadata");
|
2025-11-27 17:33:52 +02:00
|
|
|
let run_mode = matches.get_flag("run");
|
|
|
|
|
let xray_binary = matches.get_one::<String>("xray_binary").map(|s| s.as_str()).unwrap_or("xray-core");
|
2025-07-27 16:27:11 +03:30
|
|
|
|
2025-07-28 18:09:14 +03:30
|
|
|
if get_metadata {
|
|
|
|
|
print!("{}", parser::get_metadata(uri));
|
2025-07-27 16:15:04 +03:30
|
|
|
return;
|
|
|
|
|
}
|
2025-07-27 16:27:11 +03:30
|
|
|
|
|
|
|
|
let json_config = parser::create_json_config(uri, socksport, httpport);
|
2025-11-27 17:33:52 +02:00
|
|
|
|
|
|
|
|
if run_mode {
|
|
|
|
|
// Run mode: start xray-core with the config
|
|
|
|
|
let mut runner = xray_runner::XrayRunner::new();
|
|
|
|
|
|
|
|
|
|
match runner.start(&json_config, xray_binary).await {
|
|
|
|
|
Ok(()) => {
|
|
|
|
|
println!("xray-core started successfully. Press Ctrl+C to stop.");
|
|
|
|
|
|
|
|
|
|
// Wait for shutdown signal
|
|
|
|
|
xray_runner::wait_for_shutdown_signal().await;
|
|
|
|
|
|
|
|
|
|
// Stop xray-core
|
|
|
|
|
if let Err(e) = runner.stop().await {
|
|
|
|
|
eprintln!("Error stopping xray-core: {}", e);
|
|
|
|
|
} else {
|
|
|
|
|
println!("xray-core stopped successfully.");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Err(e) => {
|
|
|
|
|
eprintln!("Failed to start xray-core: {}", e);
|
|
|
|
|
std::process::exit(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Normal mode: just print the config
|
|
|
|
|
println!("{}", json_config);
|
|
|
|
|
}
|
2023-10-06 18:16:44 +03:30
|
|
|
}
|