1use crate::now_millis_i64;
2
3use super::model::{Instance, ServiceDetailDto, ServiceKey};
4use super::NamingUtils;
5use crate::common::option_utils::OptionUtils;
6use chrono::Local;
7use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
9use std::sync::Arc;
10
11#[derive(Debug, Serialize, Deserialize, Default)]
12#[serde(rename_all = "camelCase")]
13pub struct QueryListResult {
14 pub name: String,
15 pub clusters: String,
16 pub cache_millis: u64,
17 pub hosts: Vec<InstanceVO>,
18 pub last_ref_time: Option<i64>,
19 pub checksum: Option<String>,
20 #[serde(rename = "useSpecifiedURL")]
21 pub use_specified_url: Option<bool>,
22 pub env: Option<String>,
23 pub protect_threshold: Option<f32>,
24 pub reach_local_site_call_threshold: Option<bool>,
25 pub dom: Option<Arc<String>>,
26 pub metadata: Option<HashMap<String, String>>,
27}
28
29impl QueryListResult {
30 pub fn get_instance_list_string(
31 clusters: String,
32 key: &ServiceKey,
33 v: Vec<Arc<Instance>>,
34 ) -> String {
35 let now = now_millis_i64();
36 let result = Self {
37 name: key.get_join_service_name(),
38 cache_millis: 10000u64,
39 last_ref_time: Some(now),
40 checksum: Some(now.to_string()),
41 use_specified_url: Some(false),
42 clusters,
43 env: Some("".to_owned()),
44 hosts: v
45 .into_iter()
46 .map(|e| InstanceVO::from_instance(&e))
47 .collect::<Vec<_>>(),
48 dom: Some(key.service_name.to_owned()),
49 ..Default::default()
50 };
51 serde_json::to_string(&result).unwrap()
52 }
53
54 pub fn get_ref_instance_list_string(
55 clusters: String,
56 key: &ServiceKey,
57 v: Vec<&Arc<Instance>>,
58 ) -> String {
59 let now = Local::now().timestamp_millis();
60 let result = QueryListResult {
61 name: key.get_join_service_name(),
62 cache_millis: 10000u64,
63 last_ref_time: Some(now - 1000),
64 checksum: Some(now.to_string()),
65 use_specified_url: Some(false),
66 clusters,
67 env: Some("".to_owned()),
68 hosts: v
69 .into_iter()
70 .map(|e| InstanceVO::from_instance(e))
71 .collect::<Vec<_>>(),
72 dom: Some(key.service_name.to_owned()),
73 ..Default::default()
74 };
75 serde_json::to_string(&result).unwrap()
76 }
77}
78
79#[derive(Debug, Serialize, Deserialize, Default)]
80#[serde(rename_all = "camelCase")]
81pub struct InstanceVO {
82 pub service: Arc<String>,
83 pub ip: Arc<String>,
84 pub port: u32,
85 pub cluster_name: String,
86 pub weight: f32,
87 pub healthy: bool,
88 pub instance_id: Arc<String>,
89 pub metadata: Arc<HashMap<String, String>>,
90 pub marked: Option<bool>,
91 pub enabled: Option<bool>,
92 pub service_name: Option<Arc<String>>,
93 pub ephemeral: Option<bool>,
94}
95
96impl InstanceVO {
97 pub fn from_instance(instance: &Instance) -> Self {
98 Self {
99 service: instance.group_service.clone(),
100 ip: instance.ip.clone(),
101 port: instance.port,
102 cluster_name: instance.cluster_name.to_owned(),
103 weight: instance.weight,
104 healthy: instance.healthy,
105 instance_id: instance.id.clone(),
106 metadata: instance.metadata.clone(),
107 marked: Some(true),
108 enabled: Some(instance.enabled),
109 service_name: Some(instance.group_service.clone()),
111 ephemeral: Some(instance.ephemeral),
112 }
113 }
114}
115
116#[derive(Debug, Serialize, Deserialize, Default)]
117#[serde(rename_all = "camelCase")]
118pub struct ServiceQueryOptListRequest {
119 pub page_no: Option<usize>,
120 pub page_size: Option<usize>,
121 pub namespace_id: Option<String>,
122 pub group_name: Option<String>,
123 pub service_name: Option<String>,
124}
125
126#[derive(Debug, Serialize, Deserialize, Default)]
127#[serde(rename_all = "camelCase")]
128pub struct ServiceInfoParam {
129 pub namespace_id: Option<String>,
130 pub group_name: Option<String>,
131 pub service_name: Option<String>,
132 pub protect_threshold: Option<f32>,
133 pub metadata: Option<String>,
134 pub selector: Option<String>,
135}
136
137impl ServiceInfoParam {
138 pub(crate) fn merge(self, b: Self) -> Self {
139 Self {
140 namespace_id: OptionUtils::select(self.namespace_id, b.namespace_id),
141 group_name: OptionUtils::select(self.group_name, b.group_name),
142 service_name: OptionUtils::select(self.service_name, b.service_name),
143 protect_threshold: OptionUtils::select(self.protect_threshold, b.protect_threshold),
144 metadata: OptionUtils::select(self.metadata, b.metadata),
145 selector: OptionUtils::select(self.selector, b.selector),
146 }
147 }
148
149 pub(crate) fn build_service_info(self) -> anyhow::Result<ServiceDetailDto> {
150 if let Some(service_name) = self.service_name {
151 if service_name.is_empty() {
152 return Err(anyhow::anyhow!("service_name is valid"));
153 }
154 let metadata = if let Some(metadata_str) = self.metadata {
155 match NamingUtils::parse_metadata(&metadata_str) {
156 Ok(metadata) => Some(Arc::new(metadata)),
157 Err(_) => None,
158 }
159 } else {
160 None
161 };
162
163 Ok(ServiceDetailDto {
164 namespace_id: Arc::new(NamingUtils::default_namespace(
165 self.namespace_id.unwrap_or_default(),
166 )),
167 service_name: Arc::new(service_name),
168 group_name: Arc::new(NamingUtils::default_group(
169 self.group_name.unwrap_or_default(),
170 )),
171 metadata,
172 protect_threshold: self.protect_threshold,
173 ..Default::default()
174 })
175 } else {
176 Err(anyhow::anyhow!("service_name is empty"))
177 }
178 }
179}