mirror of https://github.com/ospab/ostp.git
Make --import and --url patch existing configuration instead of overwriting
This commit is contained in:
parent
b7a31af911
commit
23c4d38ee4
|
|
@ -80,6 +80,83 @@ struct Args {
|
||||||
prober: bool,
|
prober: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn patch_existing_client_config(config_path: &std::path::Path, new_client_inner: serde_json::Value) -> serde_json::Value {
|
||||||
|
let unified_new = serde_json::to_value(UnifiedConfig {
|
||||||
|
mode: AppMode::Client(new_client_inner.clone()),
|
||||||
|
version: Some(env!("CARGO_PKG_VERSION").to_string()),
|
||||||
|
log: Some(serde_json::json!({ "level": "info" })),
|
||||||
|
}).unwrap();
|
||||||
|
|
||||||
|
if !config_path.exists() {
|
||||||
|
return unified_new;
|
||||||
|
}
|
||||||
|
|
||||||
|
let content = match std::fs::read_to_string(config_path) {
|
||||||
|
Ok(c) => c,
|
||||||
|
Err(_) => return unified_new,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut stripped = json_comments::StripComments::new(content.as_bytes());
|
||||||
|
let mut existing: serde_json::Value = match serde_json::from_reader(&mut stripped) {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(_) => return unified_new,
|
||||||
|
};
|
||||||
|
|
||||||
|
if existing.get("mode").and_then(|m| m.as_str()) != Some("client") {
|
||||||
|
return unified_new;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut new_proxy = None;
|
||||||
|
if let Some(outbounds) = new_client_inner.get("outbounds").and_then(|o| o.as_array()) {
|
||||||
|
for ob in outbounds {
|
||||||
|
if ob.get("tag").and_then(|t| t.as_str()) == Some("proxy") {
|
||||||
|
new_proxy = Some(ob.clone());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(new_proxy) = new_proxy {
|
||||||
|
if let Some(existing_outbounds) = existing.get_mut("outbounds").and_then(|o| o.as_array_mut()) {
|
||||||
|
let mut replaced = false;
|
||||||
|
for ob in existing_outbounds.iter_mut() {
|
||||||
|
if ob.get("tag").and_then(|t| t.as_str()) == Some("proxy") {
|
||||||
|
*ob = new_proxy.clone();
|
||||||
|
replaced = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !replaced {
|
||||||
|
existing_outbounds.insert(0, new_proxy);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
existing["outbounds"] = serde_json::json!([new_proxy]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(new_inbounds) = new_client_inner.get("inbounds").and_then(|i| i.as_array()) {
|
||||||
|
for new_ib in new_inbounds {
|
||||||
|
if new_ib.get("type").and_then(|t| t.as_str()) == Some("tun") {
|
||||||
|
if let Some(auto_route) = new_ib.get("auto_route").and_then(|a| a.as_bool()) {
|
||||||
|
if auto_route {
|
||||||
|
if let Some(existing_inbounds) = existing.get_mut("inbounds").and_then(|i| i.as_array_mut()) {
|
||||||
|
for existing_ib in existing_inbounds.iter_mut() {
|
||||||
|
if existing_ib.get("type").and_then(|t| t.as_str()) == Some("tun") {
|
||||||
|
existing_ib["auto_route"] = serde_json::json!(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
existing["version"] = serde_json::json!(env!("CARGO_PKG_VERSION"));
|
||||||
|
|
||||||
|
existing
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_ostp_link(link: &str) -> Result<serde_json::Value> {
|
fn parse_ostp_link(link: &str) -> Result<serde_json::Value> {
|
||||||
let parsed = url::Url::parse(link)
|
let parsed = url::Url::parse(link)
|
||||||
.map_err(|e| anyhow!("Failed to parse share link URL: {e}"))?;
|
.map_err(|e| anyhow!("Failed to parse share link URL: {e}"))?;
|
||||||
|
|
@ -1224,12 +1301,8 @@ async fn run_app() -> Result<()> {
|
||||||
println!("{} Importing configuration from share link...", "[ostp]".cyan().bold());
|
println!("{} Importing configuration from share link...", "[ostp]".cyan().bold());
|
||||||
let client_cfg = parse_ostp_link(&import_url)
|
let client_cfg = parse_ostp_link(&import_url)
|
||||||
.map_err(|e| anyhow!("Share Link Error: {e}"))?;
|
.map_err(|e| anyhow!("Share Link Error: {e}"))?;
|
||||||
let unified = UnifiedConfig {
|
let patched = patch_existing_client_config(&args.config, client_cfg);
|
||||||
mode: AppMode::Client(client_cfg),
|
let content = serde_json::to_string_pretty(&patched)?;
|
||||||
version: Some("0.3.1".to_string()),
|
|
||||||
log: Some(serde_json::json!({ "level": "info" })),
|
|
||||||
};
|
|
||||||
let content = serde_json::to_string_pretty(&unified)?;
|
|
||||||
if let Some(parent) = args.config.parent() {
|
if let Some(parent) = args.config.parent() {
|
||||||
if !parent.as_os_str().is_empty() {
|
if !parent.as_os_str().is_empty() {
|
||||||
fs::create_dir_all(parent)?;
|
fs::create_dir_all(parent)?;
|
||||||
|
|
@ -1301,7 +1374,8 @@ async fn run_app() -> Result<()> {
|
||||||
client_cfg["log"]["level"] = serde_json::json!("debug");
|
client_cfg["log"]["level"] = serde_json::json!("debug");
|
||||||
}
|
}
|
||||||
|
|
||||||
return run_client_directly(client_cfg).await;
|
let patched = patch_existing_client_config(&args.config, client_cfg);
|
||||||
|
return run_client_directly(patched).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle --check: validate config and exit
|
// Handle --check: validate config and exit
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue