UX: Redesign CLI init workflow to prevent silent client-mode trap on missing configs and enrich config templates with complete modern routing schema

This commit is contained in:
ospab 2026-05-15 00:14:17 +03:00
parent 0d414e5000
commit a773422495
1 changed files with 51 additions and 17 deletions

View File

@ -140,25 +140,43 @@ async fn main() -> Result<()> {
return Ok(()); return Ok(());
} }
// Auto-generate a production config if explicitly requested via --init, or if not existing // Handle explicit configuration initialization
if args.init.is_some() || !args.config.exists() { if let Some(ref mode_str) = args.init {
let is_server = args.init.as_deref() == Some("server"); let is_server = mode_str == "server";
let dummy = if is_server { let dummy = if is_server {
UnifiedConfig { UnifiedConfig {
log_level: Some("info".to_string()), log_level: Some("info".to_string()),
mode: AppMode::Server(ServerConfig { mode: AppMode::Server(ServerConfig {
listen: "0.0.0.0:50000".to_string(), listen: "0.0.0.0:50000".to_string(),
access_keys: vec![generate_secure_key("hex")], access_keys: vec![generate_secure_key("hex")],
turn_server: None, turn_server: Some("turn.example.com:3478".to_string()),
debug: Some(false), debug: Some(false),
outbound: None, outbound: Some(OutboundConfig {
enabled: false,
protocol: "socks5".to_string(),
address: "127.0.0.1".to_string(),
port: 1080,
rules: vec![
OutboundRule {
domain_suffix: Some(vec!["google.com".to_string(), "github.com".to_string()]),
ip_cidr: Some(vec!["8.8.8.8/32".to_string()]),
action: Some("proxy".to_string()),
},
OutboundRule {
domain_suffix: Some(vec!["lan".to_string(), "local".to_string()]),
ip_cidr: Some(vec!["192.168.0.0/16".to_string()]),
action: Some("direct".to_string()),
}
],
default_action: Some("direct".to_string()),
}),
}), }),
} }
} else { } else {
UnifiedConfig { UnifiedConfig {
log_level: Some("info".to_string()), log_level: Some("info".to_string()),
mode: AppMode::Client(ClientConfig { mode: AppMode::Client(ClientConfig {
server: "127.0.0.1:50000".to_string(), server: "YOUR_SERVER_IP_HERE:50000".to_string(),
access_key: generate_secure_key("hex"), access_key: generate_secure_key("hex"),
socks5_bind: Some("127.0.0.1:1088".to_string()), socks5_bind: Some("127.0.0.1:1088".to_string()),
tun: Some(TunConfig { tun: Some(TunConfig {
@ -166,27 +184,43 @@ async fn main() -> Result<()> {
wintun_path: Some("./wintun.dll".to_string()), wintun_path: Some("./wintun.dll".to_string()),
ipv4_address: Some("10.1.0.2/24".to_string()), ipv4_address: Some("10.1.0.2/24".to_string()),
}), }),
turn: None, turn: Some(TurnConfigRaw {
enabled: false,
server_addr: "turn.example.com:3478".to_string(),
username: Some("demo_user".to_string()),
access_key: Some("demo_pass".to_string()),
}),
debug: Some(false), debug: Some(false),
exclude: Some(ExcludeConfig { exclude: Some(ExcludeConfig {
domains: Some(Vec::new()), domains: Some(vec!["localhost".to_string(), "lan".to_string()]),
ips: Some(Vec::new()), ips: Some(vec!["127.0.0.1/32".to_string(), "192.168.0.0/16".to_string()]),
processes: Some(Vec::new()), processes: Some(vec!["chrome.exe".to_string()]),
}), }),
mux: Some(MuxConfig { mux: Some(MuxConfig {
enabled: Some(false), enabled: Some(true),
sessions: Some(1), sessions: Some(4),
}), }),
}), }),
} }
}; };
fs::write(&args.config, serde_json::to_string_pretty(&dummy)?)?; fs::write(&args.config, serde_json::to_string_pretty(&dummy)?)?;
println!("Initialized configuration at {:?}", args.config); println!("🚀 Successfully initialized MODERN configuration schema at {:?}", args.config);
println!("💡 Open the file to customize outbound rules, exclusions, and credentials.");
return Ok(());
}
// If init was requested directly, terminate now. // Validate config file existence
if args.init.is_some() { if !args.config.exists() {
return Ok(()); anyhow::bail!(
} "❌ Configuration file {:?} not found.\n\n\
👉 To generate a complete production configuration template, run:\n\
\t./ostp --init server\n\
\tor\n\
\t./ostp --init client\n\n\
👉 Or specify a custom configuration file path using:\n\
\t./ostp --config /path/to/your_config.json",
args.config
);
} }
let config_content = fs::read_to_string(&args.config)?; let config_content = fs::read_to_string(&args.config)?;