1use crate::client::Client;
2use crate::errors::Error;
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6#[derive(Debug, Clone, Serialize, Deserialize)]
7pub struct PingResponse {
8 pub message: String,
9 pub version: Option<String>,
10 pub timestamp: Option<String>,
11}
12
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct ServiceInfo {
15 pub timestamp: Option<String>,
17 pub api_version: Option<String>,
19 pub message: Option<String>,
21 pub headers: HashMap<String, String>,
23}
24
25pub async fn get_service_info() -> Result<ServiceInfo, Error> {
28 let client = Client::from_global_config()?;
29
30 let response = client.get_text("ping").await?;
32
33 let mut headers = HashMap::new();
34 for (name, value) in response.headers.iter() {
35 if let Ok(value_str) = value.to_str() {
36 headers.insert(name.to_string(), value_str.to_string());
37 }
38 }
39
40 let api_version = headers
42 .get("keygen-version")
43 .or_else(|| headers.get("x-api-version"))
44 .or_else(|| headers.get("api-version"))
45 .cloned();
46
47 let timestamp = headers
49 .get("date")
50 .or_else(|| headers.get("x-timestamp"))
51 .cloned();
52
53 let message = Some(response.body.trim().to_string());
55
56 Ok(ServiceInfo {
57 timestamp,
58 api_version,
59 message,
60 headers,
61 })
62}
63
64pub fn supports_feature(service_info: &ServiceInfo, required_version: &str) -> bool {
66 if let Some(version) = &service_info.api_version {
67 version.as_str() >= required_version
69 } else {
70 true
72 }
73}
74
75pub async fn ping() -> Result<PingResponse, Error> {
77 let client = Client::from_global_config()?;
78 let response = client.get_text("ping").await?;
79
80 let message = response.body.trim().to_string();
83
84 let version = response
85 .headers
86 .get("keygen-version")
87 .and_then(|v| v.to_str().ok())
88 .map(|s| s.to_string());
89
90 let timestamp = response
91 .headers
92 .get("date")
93 .and_then(|v| v.to_str().ok())
94 .map(|s| s.to_string());
95
96 Ok(PingResponse {
97 message,
98 version,
99 timestamp,
100 })
101}
102
103pub async fn supports_product_code() -> Result<bool, Error> {
105 let service_info = get_service_info().await?;
106 Ok(supports_feature(&service_info, "1.8"))
107}
108
109#[cfg(test)]
110mod tests {
111 use super::*;
112
113 #[test]
114 fn test_supports_feature() {
115 let service_info = ServiceInfo {
116 timestamp: None,
117 api_version: Some("1.8.0".to_string()),
118 message: None,
119 headers: HashMap::new(),
120 };
121
122 assert!(supports_feature(&service_info, "1.7"));
123 assert!(supports_feature(&service_info, "1.8"));
124 assert!(!supports_feature(&service_info, "1.9"));
125 }
126}