1use serde::Deserialize;
4use trojan_config::{LoggingConfig, TcpConfig};
5
6use crate::error::ClientError;
7
8#[derive(Debug, Clone, Deserialize)]
10pub struct ClientConfig {
11 pub client: ClientSettings,
12 #[serde(default)]
13 pub logging: LoggingConfig,
14}
15
16#[derive(Debug, Clone, Deserialize)]
18pub struct ClientSettings {
19 pub listen: String,
21
22 pub remote: String,
24
25 pub password: String,
27
28 #[serde(default)]
30 pub tls: ClientTlsConfig,
31
32 #[serde(default)]
34 pub tcp: TcpConfig,
35
36 #[serde(default)]
38 pub dns: trojan_dns::DnsConfig,
39}
40
41#[derive(Debug, Clone, Deserialize)]
43pub struct ClientTlsConfig {
44 pub sni: Option<String>,
46
47 #[serde(default = "default_alpn")]
49 pub alpn: Vec<String>,
50
51 #[serde(default)]
53 pub skip_verify: bool,
54
55 pub ca: Option<String>,
57}
58
59impl Default for ClientTlsConfig {
60 fn default() -> Self {
61 Self {
62 sni: None,
63 alpn: default_alpn(),
64 skip_verify: false,
65 ca: None,
66 }
67 }
68}
69
70fn default_alpn() -> Vec<String> {
71 vec!["h2".into(), "http/1.1".into()]
72}
73
74pub fn load_client_config(path: &std::path::Path) -> Result<ClientConfig, ClientError> {
78 let content = std::fs::read_to_string(path)
79 .map_err(|e| ClientError::Config(format!("failed to read config: {e}")))?;
80
81 let ext = path.extension().and_then(|e| e.to_str()).unwrap_or("toml");
82
83 match ext {
84 "toml" => toml::from_str(&content)
85 .map_err(|e| ClientError::Config(format!("TOML parse error: {e}"))),
86 "json" | "jsonc" => {
87 let stripped: String = content
89 .lines()
90 .map(|line| {
91 if let Some(idx) = line.find("//") {
92 let before = &line[..idx];
94 let quotes = before.chars().filter(|&c| c == '"').count();
95 if quotes % 2 == 0 { before } else { line }
96 } else {
97 line
98 }
99 })
100 .collect::<Vec<_>>()
101 .join("\n");
102 serde_json::from_str(&stripped)
103 .map_err(|e| ClientError::Config(format!("JSON parse error: {e}")))
104 }
105 _ => toml::from_str(&content)
106 .map_err(|e| ClientError::Config(format!("config parse error: {e}"))),
107 }
108}