batata_client/api/
config.rs

1use std::collections::HashMap;
2
3use prost_types::Any;
4use serde::{Deserialize, Serialize};
5
6use crate::api::remote::{Request, RequestTrait, Response, ResponseTrait};
7use crate::api::Payload;
8use crate::common::CONFIG_MODULE;
9
10/// Configuration request base
11#[derive(Clone, Debug, Default, Serialize, Deserialize)]
12#[serde(rename_all = "camelCase")]
13pub struct ConfigRequest {
14    #[serde(flatten)]
15    pub request: Request,
16    pub data_id: String,
17    pub group: String,
18    pub tenant: String,
19    pub module: String,
20}
21
22impl ConfigRequest {
23    pub fn new(data_id: &str, group: &str, tenant: &str) -> Self {
24        Self {
25            request: Request::new(),
26            data_id: data_id.to_string(),
27            group: group.to_string(),
28            tenant: tenant.to_string(),
29            module: CONFIG_MODULE.to_string(),
30        }
31    }
32}
33
34impl RequestTrait for ConfigRequest {
35    fn headers(&self) -> HashMap<String, String> {
36        self.request.headers()
37    }
38
39    fn insert_headers(&mut self, headers: HashMap<String, String>) {
40        self.request.insert_headers(headers);
41    }
42
43    fn request_id(&self) -> String {
44        self.request.request_id.clone()
45    }
46}
47
48// ==================== Config Query ====================
49
50/// Configuration query request
51#[derive(Clone, Debug, Default, Serialize, Deserialize)]
52#[serde(rename_all = "camelCase")]
53pub struct ConfigQueryRequest {
54    #[serde(flatten)]
55    pub config_request: ConfigRequest,
56    pub tag: String,
57}
58
59impl ConfigQueryRequest {
60    pub fn new(data_id: &str, group: &str, tenant: &str) -> Self {
61        Self {
62            config_request: ConfigRequest::new(data_id, group, tenant),
63            tag: String::new(),
64        }
65    }
66
67    pub fn with_tag(mut self, tag: &str) -> Self {
68        self.tag = tag.to_string();
69        self
70    }
71}
72
73impl RequestTrait for ConfigQueryRequest {
74    fn headers(&self) -> HashMap<String, String> {
75        self.config_request.headers()
76    }
77
78    fn request_type(&self) -> &'static str {
79        "ConfigQueryRequest"
80    }
81
82    fn insert_headers(&mut self, headers: HashMap<String, String>) {
83        self.config_request.insert_headers(headers);
84    }
85
86    fn request_id(&self) -> String {
87        self.config_request.request_id()
88    }
89}
90
91/// Configuration query response
92#[derive(Clone, Debug, Default, Serialize, Deserialize)]
93#[serde(rename_all = "camelCase")]
94pub struct ConfigQueryResponse {
95    #[serde(flatten)]
96    pub response: Response,
97    pub content: String,
98    pub encrypted_data_key: String,
99    pub content_type: String,
100    pub md5: String,
101    pub last_modified: i64,
102    pub is_beta: bool,
103    pub tag: String,
104}
105
106impl ConfigQueryResponse {
107    pub const CONFIG_NOT_FOUND: i32 = 300;
108    pub const CONFIG_QUERY_CONFLICT: i32 = 400;
109    pub const NO_RIGHT: i32 = 403;
110}
111
112impl ResponseTrait for ConfigQueryResponse {
113    fn response_type(&self) -> &'static str {
114        "ConfigQueryResponse"
115    }
116
117    fn set_request_id(&mut self, request_id: String) {
118        self.response.request_id = request_id;
119    }
120
121    fn error_code(&self) -> i32 {
122        self.response.error_code
123    }
124
125    fn result_code(&self) -> i32 {
126        self.response.result_code
127    }
128
129    fn message(&self) -> String {
130        self.response.message.clone()
131    }
132}
133
134// ==================== Config Publish ====================
135
136/// Configuration publish request
137#[derive(Clone, Debug, Default, Serialize, Deserialize)]
138#[serde(rename_all = "camelCase")]
139pub struct ConfigPublishRequest {
140    #[serde(flatten)]
141    pub config_request: ConfigRequest,
142    pub content: String,
143    pub cas_md5: String,
144    pub addition_map: HashMap<String, String>,
145}
146
147impl ConfigPublishRequest {
148    pub fn new(data_id: &str, group: &str, tenant: &str, content: &str) -> Self {
149        Self {
150            config_request: ConfigRequest::new(data_id, group, tenant),
151            content: content.to_string(),
152            cas_md5: String::new(),
153            addition_map: HashMap::new(),
154        }
155    }
156
157    pub fn with_cas_md5(mut self, md5: &str) -> Self {
158        self.cas_md5 = md5.to_string();
159        self
160    }
161
162    pub fn with_addition(mut self, key: &str, value: &str) -> Self {
163        self.addition_map.insert(key.to_string(), value.to_string());
164        self
165    }
166
167    pub fn with_app_name(self, app_name: &str) -> Self {
168        self.with_addition("appName", app_name)
169    }
170
171    pub fn with_type(self, config_type: &str) -> Self {
172        self.with_addition("type", config_type)
173    }
174}
175
176impl RequestTrait for ConfigPublishRequest {
177    fn headers(&self) -> HashMap<String, String> {
178        self.config_request.headers()
179    }
180
181    fn request_type(&self) -> &'static str {
182        "ConfigPublishRequest"
183    }
184
185    fn insert_headers(&mut self, headers: HashMap<String, String>) {
186        self.config_request.insert_headers(headers);
187    }
188
189    fn request_id(&self) -> String {
190        self.config_request.request_id()
191    }
192}
193
194/// Configuration publish response
195#[derive(Clone, Debug, Default, Serialize, Deserialize)]
196#[serde(rename_all = "camelCase")]
197pub struct ConfigPublishResponse {
198    #[serde(flatten)]
199    pub response: Response,
200}
201
202impl ResponseTrait for ConfigPublishResponse {
203    fn response_type(&self) -> &'static str {
204        "ConfigPublishResponse"
205    }
206
207    fn set_request_id(&mut self, request_id: String) {
208        self.response.request_id = request_id;
209    }
210
211    fn error_code(&self) -> i32 {
212        self.response.error_code
213    }
214
215    fn result_code(&self) -> i32 {
216        self.response.result_code
217    }
218
219    fn message(&self) -> String {
220        self.response.message.clone()
221    }
222}
223
224// ==================== Config Remove ====================
225
226/// Configuration remove request
227#[derive(Clone, Debug, Default, Serialize, Deserialize)]
228#[serde(rename_all = "camelCase")]
229pub struct ConfigRemoveRequest {
230    #[serde(flatten)]
231    pub config_request: ConfigRequest,
232    pub tag: String,
233}
234
235impl ConfigRemoveRequest {
236    pub fn new(data_id: &str, group: &str, tenant: &str) -> Self {
237        Self {
238            config_request: ConfigRequest::new(data_id, group, tenant),
239            tag: String::new(),
240        }
241    }
242}
243
244impl RequestTrait for ConfigRemoveRequest {
245    fn headers(&self) -> HashMap<String, String> {
246        self.config_request.headers()
247    }
248
249    fn request_type(&self) -> &'static str {
250        "ConfigRemoveRequest"
251    }
252
253    fn insert_headers(&mut self, headers: HashMap<String, String>) {
254        self.config_request.insert_headers(headers);
255    }
256
257    fn request_id(&self) -> String {
258        self.config_request.request_id()
259    }
260}
261
262/// Configuration remove response
263#[derive(Clone, Debug, Default, Serialize, Deserialize)]
264#[serde(rename_all = "camelCase")]
265pub struct ConfigRemoveResponse {
266    #[serde(flatten)]
267    pub response: Response,
268}
269
270impl ResponseTrait for ConfigRemoveResponse {
271    fn response_type(&self) -> &'static str {
272        "ConfigRemoveResponse"
273    }
274
275    fn set_request_id(&mut self, request_id: String) {
276        self.response.request_id = request_id;
277    }
278
279    fn error_code(&self) -> i32 {
280        self.response.error_code
281    }
282
283    fn result_code(&self) -> i32 {
284        self.response.result_code
285    }
286
287    fn message(&self) -> String {
288        self.response.message.clone()
289    }
290}
291
292// ==================== Config Listen ====================
293
294/// Configuration listen context
295#[derive(Clone, Debug, Default, Serialize, Deserialize)]
296#[serde(rename_all = "camelCase")]
297pub struct ConfigListenContext {
298    pub group: String,
299    pub md5: String,
300    pub data_id: String,
301    pub tenant: String,
302}
303
304impl ConfigListenContext {
305    pub fn new(data_id: &str, group: &str, tenant: &str, md5: &str) -> Self {
306        Self {
307            data_id: data_id.to_string(),
308            group: group.to_string(),
309            tenant: tenant.to_string(),
310            md5: md5.to_string(),
311        }
312    }
313}
314
315/// Configuration batch listen request
316#[derive(Clone, Debug, Default, Serialize, Deserialize)]
317#[serde(rename_all = "camelCase")]
318pub struct ConfigBatchListenRequest {
319    #[serde(flatten)]
320    pub config_request: ConfigRequest,
321    pub listen: bool,
322    pub config_listen_contexts: Vec<ConfigListenContext>,
323}
324
325impl ConfigBatchListenRequest {
326    pub fn new(listen: bool) -> Self {
327        Self {
328            config_request: ConfigRequest::new("", "", ""),
329            listen,
330            config_listen_contexts: Vec::new(),
331        }
332    }
333
334    pub fn add_context(mut self, context: ConfigListenContext) -> Self {
335        self.config_listen_contexts.push(context);
336        self
337    }
338}
339
340impl RequestTrait for ConfigBatchListenRequest {
341    fn headers(&self) -> HashMap<String, String> {
342        self.config_request.headers()
343    }
344
345    fn request_type(&self) -> &'static str {
346        "ConfigBatchListenRequest"
347    }
348
349    fn insert_headers(&mut self, headers: HashMap<String, String>) {
350        self.config_request.insert_headers(headers);
351    }
352
353    fn request_id(&self) -> String {
354        self.config_request.request_id()
355    }
356}
357
358/// Changed configuration context
359#[derive(Clone, Debug, Default, Serialize, Deserialize)]
360#[serde(rename_all = "camelCase")]
361pub struct ConfigContext {
362    pub group: String,
363    pub data_id: String,
364    pub tenant: String,
365}
366
367/// Configuration change batch listen response
368#[derive(Clone, Debug, Default, Serialize, Deserialize)]
369#[serde(rename_all = "camelCase")]
370pub struct ConfigChangeBatchListenResponse {
371    #[serde(flatten)]
372    pub response: Response,
373    pub changed_configs: Vec<ConfigContext>,
374}
375
376impl ResponseTrait for ConfigChangeBatchListenResponse {
377    fn response_type(&self) -> &'static str {
378        "ConfigChangeBatchListenResponse"
379    }
380
381    fn set_request_id(&mut self, request_id: String) {
382        self.response.request_id = request_id;
383    }
384
385    fn error_code(&self) -> i32 {
386        self.response.error_code
387    }
388
389    fn result_code(&self) -> i32 {
390        self.response.result_code
391    }
392
393    fn message(&self) -> String {
394        self.response.message.clone()
395    }
396}
397
398// ==================== Config Change Notify ====================
399
400/// Configuration change notify request (from server)
401#[derive(Clone, Debug, Default, Serialize, Deserialize)]
402#[serde(rename_all = "camelCase")]
403pub struct ConfigChangeNotifyRequest {
404    #[serde(flatten)]
405    pub request: Request,
406    pub data_id: String,
407    pub group: String,
408    pub tenant: String,
409    pub module: String,
410}
411
412impl RequestTrait for ConfigChangeNotifyRequest {
413    fn headers(&self) -> HashMap<String, String> {
414        self.request.headers()
415    }
416
417    fn request_type(&self) -> &'static str {
418        "ConfigChangeNotifyRequest"
419    }
420
421    fn insert_headers(&mut self, headers: HashMap<String, String>) {
422        self.request.insert_headers(headers);
423    }
424
425    fn request_id(&self) -> String {
426        self.request.request_id()
427    }
428}
429
430/// Configuration change notify response
431#[derive(Clone, Debug, Default, Serialize, Deserialize)]
432#[serde(rename_all = "camelCase")]
433pub struct ConfigChangeNotifyResponse {
434    #[serde(flatten)]
435    pub response: Response,
436}
437
438impl ConfigChangeNotifyResponse {
439    pub fn new() -> Self {
440        Self {
441            response: Response::new(),
442        }
443    }
444}
445
446impl ResponseTrait for ConfigChangeNotifyResponse {
447    fn response_type(&self) -> &'static str {
448        "ConfigChangeNotifyResponse"
449    }
450
451    fn set_request_id(&mut self, request_id: String) {
452        self.response.request_id = request_id;
453    }
454
455    fn error_code(&self) -> i32 {
456        self.response.error_code
457    }
458
459    fn result_code(&self) -> i32 {
460        self.response.result_code
461    }
462}
463
464/// Helper function to convert response to payload
465impl ConfigChangeNotifyResponse {
466    pub fn to_payload(&self, request_id: &str) -> Payload {
467        let mut headers = HashMap::new();
468        headers.insert("requestId".to_string(), request_id.to_string());
469
470        let body = serde_json::to_vec(self).unwrap_or_default();
471
472        Payload {
473            metadata: Some(crate::api::Metadata {
474                r#type: "ConfigChangeNotifyResponse".to_string(),
475                client_ip: String::new(),
476                headers,
477            }),
478            body: Some(Any {
479                type_url: String::new(),
480                value: body,
481            }),
482        }
483    }
484}
485
486// ==================== Config Search ====================
487
488/// Configuration search request
489#[derive(Clone, Debug, Default, Serialize, Deserialize)]
490#[serde(rename_all = "camelCase")]
491pub struct ConfigSearchRequest {
492    #[serde(flatten)]
493    pub config_request: ConfigRequest,
494    pub search: String,
495    pub page_no: i32,
496    pub page_size: i32,
497}
498
499impl ConfigSearchRequest {
500    pub fn new(tenant: &str) -> Self {
501        Self {
502            config_request: ConfigRequest::new("", "", tenant),
503            search: "blur".to_string(),
504            page_no: 1,
505            page_size: 100,
506        }
507    }
508
509    /// Set data_id pattern for search
510    pub fn with_data_id(mut self, data_id: &str) -> Self {
511        self.config_request.data_id = data_id.to_string();
512        self
513    }
514
515    /// Set group pattern for search
516    pub fn with_group(mut self, group: &str) -> Self {
517        self.config_request.group = group.to_string();
518        self
519    }
520
521    /// Set pagination
522    pub fn with_page(mut self, page_no: i32, page_size: i32) -> Self {
523        self.page_no = page_no;
524        self.page_size = page_size;
525        self
526    }
527
528    /// Set search type ("blur" or "accurate")
529    pub fn with_search_type(mut self, search: &str) -> Self {
530        self.search = search.to_string();
531        self
532    }
533}
534
535impl RequestTrait for ConfigSearchRequest {
536    fn headers(&self) -> HashMap<String, String> {
537        self.config_request.headers()
538    }
539
540    fn request_type(&self) -> &'static str {
541        "ConfigSearchRequest"
542    }
543
544    fn insert_headers(&mut self, headers: HashMap<String, String>) {
545        self.config_request.insert_headers(headers);
546    }
547
548    fn request_id(&self) -> String {
549        self.config_request.request_id()
550    }
551}
552
553/// Configuration search item
554#[derive(Clone, Debug, Default, Serialize, Deserialize)]
555#[serde(rename_all = "camelCase")]
556pub struct ConfigSearchItem {
557    pub id: i64,
558    pub data_id: String,
559    pub group: String,
560    pub tenant: String,
561    pub content: String,
562    pub md5: String,
563    pub r#type: String,
564    pub app_name: String,
565    pub encrypted_data_key: String,
566}
567
568/// Configuration search response
569#[derive(Clone, Debug, Default, Serialize, Deserialize)]
570#[serde(rename_all = "camelCase")]
571pub struct ConfigSearchResponse {
572    #[serde(flatten)]
573    pub response: Response,
574    pub total_count: i32,
575    pub page_number: i32,
576    pub pages_available: i32,
577    pub page_items: Vec<ConfigSearchItem>,
578}
579
580impl ResponseTrait for ConfigSearchResponse {
581    fn response_type(&self) -> &'static str {
582        "ConfigSearchResponse"
583    }
584
585    fn set_request_id(&mut self, request_id: String) {
586        self.response.request_id = request_id;
587    }
588
589    fn error_code(&self) -> i32 {
590        self.response.error_code
591    }
592
593    fn result_code(&self) -> i32 {
594        self.response.result_code
595    }
596
597    fn message(&self) -> String {
598        self.response.message.clone()
599    }
600}
601
602// ==================== Config Info ====================
603
604/// Configuration information for caching
605#[derive(Clone, Debug, Default)]
606pub struct ConfigInfo {
607    pub data_id: String,
608    pub group: String,
609    pub tenant: String,
610    pub content: String,
611    pub md5: String,
612    pub last_modified: i64,
613    pub content_type: String,
614}
615
616impl ConfigInfo {
617    pub fn new(data_id: &str, group: &str, tenant: &str) -> Self {
618        Self {
619            data_id: data_id.to_string(),
620            group: group.to_string(),
621            tenant: tenant.to_string(),
622            ..Default::default()
623        }
624    }
625
626    pub fn key(&self) -> String {
627        crate::common::build_config_key(&self.data_id, &self.group, &self.tenant)
628    }
629
630    pub fn update_content(&mut self, content: &str) {
631        self.content = content.to_string();
632        self.md5 = crate::common::md5_hash(content);
633        self.last_modified = crate::common::current_time_millis();
634    }
635}