1use clap_serde_derive::ClapSerde;
2use serde::{Deserialize, Serialize};
3use url::Url;
4
5fn default_proxy_url() -> Url {
6 Url::parse("https://static.crates.io/crates/").unwrap()
7}
8
9fn default_index_url() -> Url {
10 Url::parse("https://index.crates.io/").unwrap()
11}
12
13fn default_api_url() -> Url {
14 Url::parse("https://crates.io/api/v1/crates/").unwrap()
15}
16
17#[derive(Debug, Deserialize, Serialize, Eq, PartialEq, Clone, ClapSerde)]
18#[serde(default)]
19pub struct Proxy {
20 #[default(false)]
22 #[arg(id = "proxy-enabled", long = "proxy-enabled")]
23 pub enabled: bool,
24
25 #[default(10)]
27 #[arg(id = "proxy-num-threads", long = "proxy-num-threads")]
28 pub num_threads: usize,
29
30 #[default(false)]
32 #[arg(id = "proxy-download-on-update", long = "proxy-download-on-update")]
33 pub download_on_update: bool,
34
35 #[default(default_proxy_url())]
37 #[arg(id = "proxy-url", long = "proxy-url")]
38 pub url: Url,
39
40 #[default(default_index_url())]
42 #[arg(id = "proxy-index", long = "proxy-index")]
43 pub index: Url,
44
45 #[default(default_api_url())]
47 #[arg(id = "proxy-api", long = "proxy-api")]
48 pub api: Url,
49
50 #[default(5)]
52 #[arg(id = "proxy-connect-timeout", long = "proxy-connect-timeout")]
53 pub connect_timeout_seconds: u64,
54
55 #[default(30)]
57 #[arg(id = "proxy-request-timeout", long = "proxy-request-timeout")]
58 pub request_timeout_seconds: u64,
59}
60
61#[cfg(test)]
62mod tests {
63 use super::*;
64
65 #[test]
66 fn default_api_url_is_cratesio() {
67 let proxy = Proxy::default();
68 assert_eq!(
69 proxy.api,
70 Url::parse("https://crates.io/api/v1/crates/").unwrap()
71 );
72 }
73
74 #[test]
75 fn deserialize_custom_api_url_from_toml() {
76 let toml = r#"
77 api = "https://rsproxy.cn/api/v1/crates/"
78 "#;
79 let proxy: Proxy = toml::from_str(toml).unwrap();
80 assert_eq!(
81 proxy.api,
82 Url::parse("https://rsproxy.cn/api/v1/crates/").unwrap()
83 );
84 }
85
86 #[test]
87 fn missing_api_url_uses_default() {
88 let toml = r#"
89 enabled = true
90 url = "https://rsproxy.cn/api/v1/crates/"
91 index = "https://rsproxy.cn/index/"
92 "#;
93 let proxy: Proxy = toml::from_str(toml).unwrap();
94 assert_eq!(
95 proxy.api,
96 Url::parse("https://crates.io/api/v1/crates/").unwrap()
97 );
98 }
99
100 #[test]
101 fn api_url_join_produces_correct_crate_url() {
102 let proxy: Proxy = toml::from_str(r#"api = "https://rsproxy.cn/api/v1/crates/""#).unwrap();
103 let url = proxy.api.join("serde").unwrap();
104 assert_eq!(url.as_str(), "https://rsproxy.cn/api/v1/crates/serde");
105 }
106
107 #[test]
108 fn default_url_join_produces_correct_crate_url() {
109 let proxy = Proxy::default();
110 let url = proxy.api.join("tokio").unwrap();
111 assert_eq!(url.as_str(), "https://crates.io/api/v1/crates/tokio");
112 }
113}