threexui_rs/models/
custom_geo.rs1use serde::{Deserialize, Deserializer, Serialize};
2
3fn null_or_vec<'de, D>(de: D) -> Result<Vec<String>, D::Error>
4where
5 D: Deserializer<'de>,
6{
7 Ok(Option::<Vec<String>>::deserialize(de)?.unwrap_or_default())
8}
9
10#[derive(Debug, Clone, Deserialize)]
11#[serde(rename_all = "camelCase")]
12pub struct CustomGeoResource {
13 pub id: i64,
14 #[serde(rename = "type")]
15 pub geo_type: String,
16 pub alias: String,
17 pub url: String,
18 #[serde(default)]
19 pub local_path: String,
20 #[serde(default)]
21 pub last_updated_at: i64,
22 #[serde(default)]
23 pub created_at: i64,
24 #[serde(default)]
25 pub updated_at: i64,
26}
27
28#[derive(Debug, Clone, Serialize)]
29pub struct CreateCustomGeo {
30 #[serde(rename = "type")]
31 pub geo_type: String,
32 pub alias: String,
33 pub url: String,
34}
35
36#[derive(Debug, Clone, Default, Deserialize)]
37pub struct CustomGeoAliases {
38 #[serde(default, deserialize_with = "null_or_vec")]
39 pub geosite: Vec<String>,
40 #[serde(default, deserialize_with = "null_or_vec")]
41 pub geoip: Vec<String>,
42}
43
44#[cfg(test)]
45mod tests {
46 use super::*;
47
48 #[test]
49 fn custom_geo_deserializes() {
50 let raw = r#"{"id":1,"type":"geoip","alias":"myip","url":"https://example.com/ip.dat","localPath":"","lastUpdatedAt":0,"createdAt":0,"updatedAt":0}"#;
51 let r: CustomGeoResource = serde_json::from_str(raw).unwrap();
52 assert_eq!(r.id, 1);
53 assert_eq!(r.geo_type, "geoip");
54 assert_eq!(r.alias, "myip");
55 }
56}