batata_client/api/
naming.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::{NAMING_MODULE, REGISTER_INSTANCE, DEREGISTER_INSTANCE, UPDATE_INSTANCE};
9
10// ==================== Instance ====================
11
12/// Service instance information
13#[derive(Clone, Debug, Default, Serialize, Deserialize)]
14#[serde(rename_all = "camelCase")]
15pub struct Instance {
16    pub instance_id: String,
17    pub ip: String,
18    pub port: i32,
19    pub weight: f64,
20    pub healthy: bool,
21    pub enabled: bool,
22    pub ephemeral: bool,
23    pub cluster_name: String,
24    pub service_name: String,
25    pub metadata: HashMap<String, String>,
26    pub instance_heart_beat_interval: i64,
27    pub instance_heart_beat_time_out: i64,
28    pub ip_delete_timeout: i64,
29    pub instance_id_generator: String,
30}
31
32impl Instance {
33    pub fn new(ip: &str, port: i32) -> Self {
34        Self {
35            ip: ip.to_string(),
36            port,
37            weight: 1.0,
38            healthy: true,
39            enabled: true,
40            ephemeral: true,
41            cluster_name: crate::common::DEFAULT_CLUSTER.to_string(),
42            metadata: HashMap::new(),
43            instance_heart_beat_interval: 5000,
44            instance_heart_beat_time_out: 15000,
45            ip_delete_timeout: 30000,
46            ..Default::default()
47        }
48    }
49
50    pub fn with_weight(mut self, weight: f64) -> Self {
51        self.weight = weight;
52        self
53    }
54
55    pub fn with_cluster(mut self, cluster: &str) -> Self {
56        self.cluster_name = cluster.to_string();
57        self
58    }
59
60    pub fn with_metadata(mut self, key: &str, value: &str) -> Self {
61        self.metadata.insert(key.to_string(), value.to_string());
62        self
63    }
64
65    pub fn with_ephemeral(mut self, ephemeral: bool) -> Self {
66        self.ephemeral = ephemeral;
67        self
68    }
69
70    pub fn with_enabled(mut self, enabled: bool) -> Self {
71        self.enabled = enabled;
72        self
73    }
74
75    /// Generate instance ID if not set
76    pub fn generate_instance_id(&mut self) {
77        if self.instance_id.is_empty() {
78            self.instance_id = format!("{}#{}#{}", self.ip, self.port, self.cluster_name);
79        }
80    }
81
82    /// Get the instance key
83    pub fn key(&self) -> String {
84        format!("{}#{}#{}", self.ip, self.port, self.cluster_name)
85    }
86}
87
88// ==================== Service ====================
89
90/// Service information
91#[derive(Clone, Debug, Default, Serialize, Deserialize)]
92#[serde(rename_all = "camelCase")]
93pub struct Service {
94    pub name: String,
95    pub group_name: String,
96    pub clusters: String,
97    pub cache_millis: i64,
98    pub hosts: Vec<Instance>,
99    pub last_ref_time: i64,
100    pub checksum: String,
101    pub all_ips: bool,
102    pub reach_protection_threshold: bool,
103}
104
105impl Service {
106    pub fn new(name: &str, group_name: &str) -> Self {
107        Self {
108            name: name.to_string(),
109            group_name: group_name.to_string(),
110            cache_millis: 10000,
111            hosts: Vec::new(),
112            ..Default::default()
113        }
114    }
115
116    pub fn key(&self) -> String {
117        format!("{}@@{}", self.group_name, self.name)
118    }
119
120    /// Get healthy instances
121    pub fn healthy_instances(&self) -> Vec<&Instance> {
122        self.hosts.iter().filter(|i| i.healthy && i.enabled).collect()
123    }
124
125    /// Get all enabled instances
126    pub fn enabled_instances(&self) -> Vec<&Instance> {
127        self.hosts.iter().filter(|i| i.enabled).collect()
128    }
129}
130
131// ==================== Naming Request Base ====================
132
133/// Base naming request
134#[derive(Clone, Debug, Default, Serialize, Deserialize)]
135#[serde(rename_all = "camelCase")]
136pub struct NamingRequest {
137    #[serde(flatten)]
138    pub request: Request,
139    pub namespace: String,
140    pub service_name: String,
141    pub group_name: String,
142    pub module: String,
143}
144
145impl NamingRequest {
146    pub fn new(namespace: &str, service_name: &str, group_name: &str) -> Self {
147        Self {
148            request: Request::new(),
149            namespace: namespace.to_string(),
150            service_name: service_name.to_string(),
151            group_name: group_name.to_string(),
152            module: NAMING_MODULE.to_string(),
153        }
154    }
155}
156
157impl RequestTrait for NamingRequest {
158    fn headers(&self) -> HashMap<String, String> {
159        self.request.headers()
160    }
161
162    fn insert_headers(&mut self, headers: HashMap<String, String>) {
163        self.request.insert_headers(headers);
164    }
165
166    fn request_id(&self) -> String {
167        self.request.request_id.clone()
168    }
169}
170
171// ==================== Instance Request ====================
172
173/// Instance registration/deregistration request
174#[derive(Clone, Debug, Default, Serialize, Deserialize)]
175#[serde(rename_all = "camelCase")]
176pub struct InstanceRequest {
177    #[serde(flatten)]
178    pub naming_request: NamingRequest,
179    pub r#type: String,
180    pub instance: Instance,
181}
182
183impl InstanceRequest {
184    pub fn register(namespace: &str, service_name: &str, group_name: &str, instance: Instance) -> Self {
185        Self {
186            naming_request: NamingRequest::new(namespace, service_name, group_name),
187            r#type: REGISTER_INSTANCE.to_string(),
188            instance,
189        }
190    }
191
192    pub fn deregister(namespace: &str, service_name: &str, group_name: &str, instance: Instance) -> Self {
193        Self {
194            naming_request: NamingRequest::new(namespace, service_name, group_name),
195            r#type: DEREGISTER_INSTANCE.to_string(),
196            instance,
197        }
198    }
199
200    pub fn update(namespace: &str, service_name: &str, group_name: &str, instance: Instance) -> Self {
201        Self {
202            naming_request: NamingRequest::new(namespace, service_name, group_name),
203            r#type: UPDATE_INSTANCE.to_string(),
204            instance,
205        }
206    }
207}
208
209impl RequestTrait for InstanceRequest {
210    fn headers(&self) -> HashMap<String, String> {
211        self.naming_request.headers()
212    }
213
214    fn request_type(&self) -> &'static str {
215        "InstanceRequest"
216    }
217
218    fn insert_headers(&mut self, headers: HashMap<String, String>) {
219        self.naming_request.insert_headers(headers);
220    }
221
222    fn request_id(&self) -> String {
223        self.naming_request.request_id()
224    }
225}
226
227/// Instance response
228#[derive(Clone, Debug, Default, Serialize, Deserialize)]
229#[serde(rename_all = "camelCase")]
230pub struct InstanceResponse {
231    #[serde(flatten)]
232    pub response: Response,
233    pub r#type: String,
234}
235
236impl ResponseTrait for InstanceResponse {
237    fn response_type(&self) -> &'static str {
238        "InstanceResponse"
239    }
240
241    fn set_request_id(&mut self, request_id: String) {
242        self.response.request_id = request_id;
243    }
244
245    fn error_code(&self) -> i32 {
246        self.response.error_code
247    }
248
249    fn result_code(&self) -> i32 {
250        self.response.result_code
251    }
252
253    fn message(&self) -> String {
254        self.response.message.clone()
255    }
256}
257
258// ==================== Batch Instance Request ====================
259
260/// Batch instance request
261#[derive(Clone, Debug, Default, Serialize, Deserialize)]
262#[serde(rename_all = "camelCase")]
263pub struct BatchInstanceRequest {
264    #[serde(flatten)]
265    pub naming_request: NamingRequest,
266    pub r#type: String,
267    pub instances: Vec<Instance>,
268}
269
270impl BatchInstanceRequest {
271    pub fn register(namespace: &str, service_name: &str, group_name: &str, instances: Vec<Instance>) -> Self {
272        Self {
273            naming_request: NamingRequest::new(namespace, service_name, group_name),
274            r#type: REGISTER_INSTANCE.to_string(),
275            instances,
276        }
277    }
278
279    pub fn deregister(namespace: &str, service_name: &str, group_name: &str, instances: Vec<Instance>) -> Self {
280        Self {
281            naming_request: NamingRequest::new(namespace, service_name, group_name),
282            r#type: DEREGISTER_INSTANCE.to_string(),
283            instances,
284        }
285    }
286}
287
288impl RequestTrait for BatchInstanceRequest {
289    fn headers(&self) -> HashMap<String, String> {
290        self.naming_request.headers()
291    }
292
293    fn request_type(&self) -> &'static str {
294        "BatchInstanceRequest"
295    }
296
297    fn insert_headers(&mut self, headers: HashMap<String, String>) {
298        self.naming_request.insert_headers(headers);
299    }
300
301    fn request_id(&self) -> String {
302        self.naming_request.request_id()
303    }
304}
305
306/// Batch instance response
307#[derive(Clone, Debug, Default, Serialize, Deserialize)]
308#[serde(rename_all = "camelCase")]
309pub struct BatchInstanceResponse {
310    #[serde(flatten)]
311    pub response: Response,
312    pub r#type: String,
313}
314
315impl ResponseTrait for BatchInstanceResponse {
316    fn response_type(&self) -> &'static str {
317        "BatchInstanceResponse"
318    }
319
320    fn set_request_id(&mut self, request_id: String) {
321        self.response.request_id = request_id;
322    }
323
324    fn error_code(&self) -> i32 {
325        self.response.error_code
326    }
327
328    fn result_code(&self) -> i32 {
329        self.response.result_code
330    }
331
332    fn message(&self) -> String {
333        self.response.message.clone()
334    }
335}
336
337// ==================== Service Query ====================
338
339/// Service query request
340#[derive(Clone, Debug, Default, Serialize, Deserialize)]
341#[serde(rename_all = "camelCase")]
342pub struct ServiceQueryRequest {
343    #[serde(flatten)]
344    pub naming_request: NamingRequest,
345    pub cluster: String,
346    pub healthy_only: bool,
347    pub udp_port: i32,
348}
349
350impl ServiceQueryRequest {
351    pub fn new(namespace: &str, service_name: &str, group_name: &str) -> Self {
352        Self {
353            naming_request: NamingRequest::new(namespace, service_name, group_name),
354            cluster: String::new(),
355            healthy_only: false,
356            udp_port: 0,
357        }
358    }
359
360    pub fn with_cluster(mut self, cluster: &str) -> Self {
361        self.cluster = cluster.to_string();
362        self
363    }
364
365    pub fn with_healthy_only(mut self, healthy_only: bool) -> Self {
366        self.healthy_only = healthy_only;
367        self
368    }
369}
370
371impl RequestTrait for ServiceQueryRequest {
372    fn headers(&self) -> HashMap<String, String> {
373        self.naming_request.headers()
374    }
375
376    fn request_type(&self) -> &'static str {
377        "ServiceQueryRequest"
378    }
379
380    fn insert_headers(&mut self, headers: HashMap<String, String>) {
381        self.naming_request.insert_headers(headers);
382    }
383
384    fn request_id(&self) -> String {
385        self.naming_request.request_id()
386    }
387}
388
389/// Query service response
390#[derive(Clone, Debug, Default, Serialize, Deserialize)]
391#[serde(rename_all = "camelCase")]
392pub struct QueryServiceResponse {
393    #[serde(flatten)]
394    pub response: Response,
395    pub service_info: Service,
396}
397
398impl ResponseTrait for QueryServiceResponse {
399    fn response_type(&self) -> &'static str {
400        "QueryServiceResponse"
401    }
402
403    fn set_request_id(&mut self, request_id: String) {
404        self.response.request_id = request_id;
405    }
406
407    fn error_code(&self) -> i32 {
408        self.response.error_code
409    }
410
411    fn result_code(&self) -> i32 {
412        self.response.result_code
413    }
414
415    fn message(&self) -> String {
416        self.response.message.clone()
417    }
418}
419
420// ==================== Service List ====================
421
422/// Service list request
423#[derive(Clone, Debug, Default, Serialize, Deserialize)]
424#[serde(rename_all = "camelCase")]
425pub struct ServiceListRequest {
426    #[serde(flatten)]
427    pub naming_request: NamingRequest,
428    pub page_no: i32,
429    pub page_size: i32,
430    pub selector: String,
431}
432
433impl ServiceListRequest {
434    pub fn new(namespace: &str, group_name: &str) -> Self {
435        Self {
436            naming_request: NamingRequest::new(namespace, "", group_name),
437            page_no: 1,
438            page_size: 100,
439            selector: String::new(),
440        }
441    }
442
443    pub fn with_page(mut self, page_no: i32, page_size: i32) -> Self {
444        self.page_no = page_no;
445        self.page_size = page_size;
446        self
447    }
448}
449
450impl RequestTrait for ServiceListRequest {
451    fn headers(&self) -> HashMap<String, String> {
452        self.naming_request.headers()
453    }
454
455    fn request_type(&self) -> &'static str {
456        "ServiceListRequest"
457    }
458
459    fn insert_headers(&mut self, headers: HashMap<String, String>) {
460        self.naming_request.insert_headers(headers);
461    }
462
463    fn request_id(&self) -> String {
464        self.naming_request.request_id()
465    }
466}
467
468/// Service list response
469#[derive(Clone, Debug, Default, Serialize, Deserialize)]
470#[serde(rename_all = "camelCase")]
471pub struct ServiceListResponse {
472    #[serde(flatten)]
473    pub response: Response,
474    pub count: i32,
475    pub service_names: Vec<String>,
476}
477
478impl ResponseTrait for ServiceListResponse {
479    fn response_type(&self) -> &'static str {
480        "ServiceListResponse"
481    }
482
483    fn set_request_id(&mut self, request_id: String) {
484        self.response.request_id = request_id;
485    }
486
487    fn error_code(&self) -> i32 {
488        self.response.error_code
489    }
490
491    fn result_code(&self) -> i32 {
492        self.response.result_code
493    }
494
495    fn message(&self) -> String {
496        self.response.message.clone()
497    }
498}
499
500// ==================== Subscribe Service ====================
501
502/// Subscribe service request
503#[derive(Clone, Debug, Default, Serialize, Deserialize)]
504#[serde(rename_all = "camelCase")]
505pub struct SubscribeServiceRequest {
506    #[serde(flatten)]
507    pub naming_request: NamingRequest,
508    pub subscribe: bool,
509    pub clusters: String,
510}
511
512impl SubscribeServiceRequest {
513    pub fn subscribe(namespace: &str, service_name: &str, group_name: &str) -> Self {
514        Self {
515            naming_request: NamingRequest::new(namespace, service_name, group_name),
516            subscribe: true,
517            clusters: String::new(),
518        }
519    }
520
521    pub fn unsubscribe(namespace: &str, service_name: &str, group_name: &str) -> Self {
522        Self {
523            naming_request: NamingRequest::new(namespace, service_name, group_name),
524            subscribe: false,
525            clusters: String::new(),
526        }
527    }
528
529    pub fn with_clusters(mut self, clusters: &str) -> Self {
530        self.clusters = clusters.to_string();
531        self
532    }
533}
534
535impl RequestTrait for SubscribeServiceRequest {
536    fn headers(&self) -> HashMap<String, String> {
537        self.naming_request.headers()
538    }
539
540    fn request_type(&self) -> &'static str {
541        "SubscribeServiceRequest"
542    }
543
544    fn insert_headers(&mut self, headers: HashMap<String, String>) {
545        self.naming_request.insert_headers(headers);
546    }
547
548    fn request_id(&self) -> String {
549        self.naming_request.request_id()
550    }
551}
552
553/// Subscribe service response
554#[derive(Clone, Debug, Default, Serialize, Deserialize)]
555#[serde(rename_all = "camelCase")]
556pub struct SubscribeServiceResponse {
557    #[serde(flatten)]
558    pub response: Response,
559    pub service_info: Service,
560}
561
562impl ResponseTrait for SubscribeServiceResponse {
563    fn response_type(&self) -> &'static str {
564        "SubscribeServiceResponse"
565    }
566
567    fn set_request_id(&mut self, request_id: String) {
568        self.response.request_id = request_id;
569    }
570
571    fn error_code(&self) -> i32 {
572        self.response.error_code
573    }
574
575    fn result_code(&self) -> i32 {
576        self.response.result_code
577    }
578
579    fn message(&self) -> String {
580        self.response.message.clone()
581    }
582}
583
584// ==================== Notify Subscriber ====================
585
586/// Notify subscriber request (from server)
587#[derive(Clone, Debug, Default, Serialize, Deserialize)]
588#[serde(rename_all = "camelCase")]
589pub struct NotifySubscriberRequest {
590    #[serde(flatten)]
591    pub request: Request,
592    pub namespace: String,
593    pub service_name: String,
594    pub group_name: String,
595    pub service_info: Service,
596    pub module: String,
597}
598
599impl RequestTrait for NotifySubscriberRequest {
600    fn headers(&self) -> HashMap<String, String> {
601        self.request.headers()
602    }
603
604    fn request_type(&self) -> &'static str {
605        "NotifySubscriberRequest"
606    }
607
608    fn insert_headers(&mut self, headers: HashMap<String, String>) {
609        self.request.insert_headers(headers);
610    }
611
612    fn request_id(&self) -> String {
613        self.request.request_id()
614    }
615}
616
617/// Notify subscriber response
618#[derive(Clone, Debug, Default, Serialize, Deserialize)]
619#[serde(rename_all = "camelCase")]
620pub struct NotifySubscriberResponse {
621    #[serde(flatten)]
622    pub response: Response,
623}
624
625impl NotifySubscriberResponse {
626    pub fn new() -> Self {
627        Self {
628            response: Response::new(),
629        }
630    }
631
632    pub fn to_payload(&self, request_id: &str) -> Payload {
633        let mut headers = HashMap::new();
634        headers.insert("requestId".to_string(), request_id.to_string());
635
636        let body = serde_json::to_vec(self).unwrap_or_default();
637
638        Payload {
639            metadata: Some(crate::api::Metadata {
640                r#type: "NotifySubscriberResponse".to_string(),
641                client_ip: String::new(),
642                headers,
643            }),
644            body: Some(Any {
645                type_url: String::new(),
646                value: body,
647            }),
648        }
649    }
650}
651
652impl ResponseTrait for NotifySubscriberResponse {
653    fn response_type(&self) -> &'static str {
654        "NotifySubscriberResponse"
655    }
656
657    fn set_request_id(&mut self, request_id: String) {
658        self.response.request_id = request_id;
659    }
660
661    fn error_code(&self) -> i32 {
662        self.response.error_code
663    }
664
665    fn result_code(&self) -> i32 {
666        self.response.result_code
667    }
668}