Skip to main content

ri/c/
service_mesh.rs

1//! Copyright © 2025-2026 Wenze Wei. All Rights Reserved.
2//!
3//! This file is part of Ri.
4//! The Ri project belongs to the Dunimd Team.
5//!
6//! Licensed under the Apache License, Version 2.0 (the "License");
7//! You may not use this file except in compliance with the License.
8//! You may obtain a copy of the License at
9//!
10//!     http://www.apache.org/licenses/LICENSE-2.0
11//!
12//! Unless required by applicable law or agreed to in writing, software
13//! distributed under the License is distributed on an "AS IS" BASIS,
14//! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15//! See the License for the specific language governing permissions and
16//! limitations under the License.
17
18//! # Service Mesh Module C API
19//!
20//! This module provides C language bindings for Ri's service mesh infrastructure. The service mesh
21//! module delivers comprehensive service-to-service communication capabilities including service discovery,
22//! load balancing, circuit breaking, traffic routing, and observability for distributed systems. This
23//! C API enables C/C++ applications to leverage Ri's service mesh functionality for building resilient,
24//! observable, and manageable microservices architectures.
25//!
26//! ## Module Architecture
27//!
28//! The service mesh module comprises three primary components that together provide complete service
29//! management capabilities:
30//!
31//! - **RiServiceMesh**: Central service mesh controller managing service registry, traffic routing,
32//!   and communication policies across all connected services. The mesh controller handles the complete
33//!   lifecycle of service communication including discovery, routing, load balancing, and failure handling.
34//!
35//! - **RiServiceMeshConfig**: Configuration container for service mesh parameters including discovery
36//!   settings, traffic management policies, circuit breaker thresholds, and observability options.
37//!   The configuration object controls mesh behavior, resource allocation, and operational characteristics.
38//!
39//! - **RiServiceEndpoint**: Individual service endpoint representation within the mesh, tracking
40//!   service instance metadata, health status, load metrics, and communication properties. Endpoints
41//!   represent actual running instances of services that can receive traffic.
42//!
43//! ## Service Discovery
44//!
45//! The service mesh provides automatic service discovery capabilities:
46//!
47//! - **Service Registration**: Services automatically register with the mesh when they start,
48//!   advertising their network location, port, and metadata. Registration includes health check
49//!   endpoints and load reporting.
50//!
51//! - **Instance Tracking**: The mesh maintains a live registry of all service instances with
52//!   real-time health status, load metrics, and topology information.
53//!
54//! - **DNS-Based Discovery**: Services discover each other using DNS-like naming conventions.
55//!   Service names resolve to healthy instances based on routing policies.
56//!
57//! - **Health Checking**: Automatic health checks verify service instance availability. Unhealthy
58//!   instances are removed from the load balancer rotation until they recover.
59//!
60//! - **Service Metadata**: Rich metadata attached to service registrations including version, zone,
61//!   cluster, and custom labels for sophisticated routing decisions.
62//!
63//! ## Traffic Management
64//!
65//! The mesh implements sophisticated traffic routing:
66//!
67//! - **Load Balancing**: Multiple load balancing algorithms including round-robin, least-connections,
68//!   weighted distribution, and consistent hashing for session affinity.
69//!
70//! - **Canary Deployments**: Gradual traffic shifting between service versions for safe rollouts.
71//!   Configure percentage-based or rules-based traffic splitting.
72//!
73//! - **A/B Testing**: Route specific percentages of traffic to different service versions
74//!   for testing new features with production traffic.
75//!
76//! - **Blue-Green Deployments**: Zero-downtime deployments by switching traffic between complete
77//!   service environments. Enables instant rollback capability.
78//!
79//! - **Traffic Mirroring**: Copy production traffic to shadow services for testing without
80//!   affecting production responses. Useful for validating new service versions.
81//!
82//! - **Retries and Timeouts**: Configurable retry policies and timeout values for all
83//!   service-to-service calls. Automatic retry for idempotent operations.
84//!
85//! ## Circuit Breaking
86//!
87//! The service mesh implements circuit breaker patterns for failure isolation:
88//!
89//! - **Failure Detection**: Automatic detection of downstream service failures through
90//!   error rates, latency percentiles, and custom health indicators.
91//!
92//! - **Open Circuit**: When failure threshold is exceeded, the circuit opens and requests
93//!   immediately fail without making downstream calls. Prevents cascade failures.
94//!
95//! - **Half-Open State**: After cooldown period, limited requests are allowed through to
96//!   test if the downstream service has recovered.
97//!
98//! - **Close Circuit**: Successful responses during half-open state close the circuit
99//!   and restore normal operation.
100//!
101//! - **Configuration**: Tunable failure thresholds, timeout values, and volume thresholds
102//!   for each service dependency.
103//!
104//! - **Fallback Handling**: Configurable fallback responses or alternative service calls
105//!   when circuit is open. Enables graceful degradation.
106//!
107//! ## Resilience Patterns
108//!
109//! The mesh provides comprehensive resilience mechanisms:
110//!
111//! - **Bulkhead Isolation**: Isolate critical resources by limiting concurrent requests
112//!   to downstream services. Prevents one slow service from affecting others.
113//!
114//! - **Rate Limiting**: Per-service and per-instance rate limits prevent overload scenarios.
115//!   Supports token bucket and sliding window algorithms.
116//!
117//! - **Retry Policies**: Configurable retry attempts, backoff strategies (fixed, exponential,
118//!   jitter), and retry conditions (5xx, timeouts, connection failures).
119//!
120//! - **Timeout Management**: End-to-end timeout propagation ensures requests don't wait
121//!   indefinitely. Supports deadline propagation across service boundaries.
122//!
123//! ## Security
124//!
125//! The service mesh implements zero-trust security principles:
126//!
127//! - **mTLS Encryption**: Automatic mutual TLS encryption for all service-to-service
128//!   communication. Certificates automatically rotated and validated.
129//!
130//! - **Service Identity**: Strong identity verification using SPIFFE-style identifiers.
131//!   Each service has verifiable credentials independent of network location.
132//!
133//! - **Authorization Policies**: Fine-grained access control policies defining which
134//!   services can communicate. Default deny-all policy with explicit allow rules.
135//!
136//! - **Authentication**: JWT validation, OAuth token exchange, and custom authentication
137//!   mechanisms integrated at the mesh layer.
138//!
139//! - **Network Policies**: L3/L4 network filtering restricting communication between
140//!   services based on identity and metadata.
141//!
142//! ## Observability
143//!
144//! The mesh provides comprehensive observability features:
145//!
146//! - **Traffic Metrics**: Request rates, latencies (p50, p95, p99), and error rates
147//!   for all service-to-service communication.
148//!
149//! - **Distributed Tracing**: Automatic trace context propagation across service
150//!   boundaries with W3C Trace Context standard.
151//!
152//! - **Service Graph**: Real-time visualization of service topology and communication
153//!   patterns. Identifies dependencies and communication bottlenecks.
154//!
155//! - **Access Logging**: Detailed logs of all service-to-service communication including
156//!   headers, status codes, and timing information.
157//!
158//! - **Custom Metrics**: User-defined metrics collected at the mesh layer independent
159//!   of application code.
160//!
161//! ## Performance Characteristics
162//!
163//! Service mesh operations are optimized for minimal overhead:
164//!
165//! - **Sidecar Pattern**: Lightweight proxy (Envoy) deployed alongside each service instance.
166//!   Intercepts all traffic with minimal latency overhead.
167//!
168//! - **xDS Configuration**: Efficient configuration distribution using xDS (discovery services)
169//!   protocol. Changes propagate in seconds across the mesh.
170//!
171//! - **Connection Pooling**: Efficient connection management to upstream services with
172//!   configurable pool sizes and connection limits.
173//!
174//! - **Batching and Buffering**: Request batching and response buffering optimize throughput
175//!   while maintaining latency SLAs.
176//!
177//! - **Zero-Copy**: Modern data plane implementations use zero-copy techniques where
178//!   possible to minimize CPU overhead.
179//!
180//! ## Memory Management
181//!
182//! All C API objects use opaque pointers with manual memory management:
183//!
184//! - Constructor functions allocate new instances on the heap
185//! - Destructor functions must be called to release memory
186//! - Service endpoints are managed by the mesh controller
187//! - Configuration objects control mesh-wide settings
188//!
189//! ## Thread Safety
190//!
191//! The underlying implementations are thread-safe:
192//!
193//! - Concurrent service registration from multiple instances supported
194//! - Route configuration updates atomic across the mesh
195//! - Load balancing decisions thread-safe
196//! - Metrics collection lock-free for performance
197//!
198//! ## Usage Example
199//!
200//! ```c
201//! // Create service mesh configuration
202//! RiServiceMeshConfig* config = ri_service_mesh_config_new();
203//! if (config == NULL) {
204//!     fprintf(stderr, "Failed to create service mesh config\n");
205//!     return ERROR_INIT;
206//! }
207//!
208//! // Configure mesh settings
209//! ri_service_mesh_config_set_enable_mtls(config, true);
210//! ri_service_mesh_config_set_enable_circuit_breaker(config, true);
211//! ri_service_mesh_config_set_enable_tracing(config, true);
212//! ri_service_mesh_config_set_enable_metrics(config, true);
213//!
214//! // Configure circuit breaker
215//! ri_service_mesh_config_set_circuit_breaker_failure_rate(config, 0.5);
216//! ri_service_mesh_config_set_circuit_breaker_timeout_ms(config, 30000);
217//!
218//! // Configure load balancing
219//! ri_service_mesh_config_set_load_balancing_algorithm(config, LB_LEAST_REQUESTS);
220//!
221//! // Create service mesh controller
222//! RiServiceMesh* mesh = ri_service_mesh_new(config);
223//! if (mesh == NULL) {
224//!     fprintf(stderr, "Failed to create service mesh\n");
225//!     ri_service_mesh_config_free(config);
226//!     return ERROR_INIT;
227//! }
228//!
229//! // Start the mesh controller
230//! int result = ri_service_mesh_start(mesh);
231//! if (result != 0) {
232//!     fprintf(stderr, "Failed to start service mesh: %d\n", result);
233//!     ri_service_mesh_free(mesh);
234//!     ri_service_mesh_config_free(config);
235//!     return ERROR_START;
236//! }
237//!
238//! printf("Service mesh started successfully\n");
239//!
240//! // Register a service endpoint
241//! RiServiceEndpoint* endpoint = ri_service_endpoint_new();
242//! if (endpoint == NULL) {
243//!     fprintf(stderr, "Failed to create service endpoint\n");
244//!     ri_service_mesh_stop(mesh);
245//!     ri_service_mesh_free(mesh);
246//!     ri_service_mesh_config_free(config);
247//!     return ERROR_INIT;
248//! }
249//!
250//! ri_service_endpoint_set_name(endpoint, "user-service");
251//! ri_service_endpoint_set_host(endpoint, "10.0.1.5");
252//! ri_service_endpoint_set_port(endpoint, 8080);
253//! ri_service_endpoint_set_version(endpoint, "v1.2.3");
254//! ri_service_endpoint_set_health_check_url(endpoint, "/health");
255//!
256//! result = ri_service_mesh_register(mesh, endpoint);
257//! if (result != 0) {
258//!     fprintf(stderr, "Failed to register endpoint: %d\n", result);
259//!     ri_service_endpoint_free(endpoint);
260//! } else {
261//!     printf("Service endpoint registered successfully\n");
262//! }
263//!
264//! // Get service information
265//! const char* service_name = ri_service_endpoint_get_name(endpoint);
266//! const char* service_version = ri_service_endpoint_get_version(endpoint);
267//! uint32_t healthy_count = ri_service_mesh_get_healthy_count(mesh, service_name);
268//!
269//! printf("Service: %s (version: %s), healthy instances: %u\n",
270//!        service_name, service_version, healthy_count);
271//!
272//! // Discover a service
273//! RiServiceEndpoint* discovered = NULL;
274//! result = ri_service_mesh_discover(mesh, "user-service", &discovered);
275//!
276//! if (result == 0 && discovered != NULL) {
277//!     const char* host = ri_service_endpoint_get_host(discovered);
278//!     uint16_t port = ri_service_endpoint_get_port(discovered);
279//!
280//!     printf("Discovered service at %s:%d\n", host, port);
281//!
282//!     ri_service_endpoint_free(discovered);
283//! }
284//!
285//! // Update service mesh configuration at runtime
286//! ri_service_mesh_config_set_circuit_breaker_failure_rate(mesh, 0.3);
287//! ri_service_mesh_reload_config(mesh);
288//!
289//! // Get service mesh statistics
290//! uint64_t total_requests = ri_service_mesh_get_total_requests(mesh);
291//! uint64_t failed_requests = ri_service_mesh_get_failed_requests(mesh);
292//!
293//! printf("Mesh stats: %lu total requests, %lu failed\n",
294//!        total_requests, failed_requests);
295//!
296//! // Deregister service when shutting down
297//! ri_service_mesh_deregister(mesh, endpoint);
298//!
299//! // Graceful shutdown
300//! ri_service_mesh_stop(mesh);
301//! ri_service_endpoint_free(endpoint);
302//! ri_service_mesh_free(mesh);
303//! ri_service_mesh_config_free(config);
304//!
305//! printf("Service mesh shutdown complete\n");
306//! ```
307//!
308//! ## Dependencies
309//!
310//! This module depends on the following Ri components:
311//!
312//! - `crate::service_mesh`: Rust service mesh module implementation
313//! - `crate::prelude`: Common types and traits
314//! - Envoy proxy for data plane (embedded or external)
315//! - xDS protocol stack for configuration management
316//!
317//! ## Feature Flags
318//!
319//! The service mesh module is enabled by the "service-mesh" feature flag.
320//! Disable this feature to reduce binary size when service mesh is not required.
321//!
322//! Additional features:
323//!
324//! - `service-mesh-mtls`: Enable mutual TLS encryption
325//! - `service-mesh-circuit-breaker`: Enable circuit breaker functionality
326//! - `service-mesh-tracing`: Enable distributed tracing
327//! - `service-mesh-metrics`: Enable metrics collection
328//! - `service-mesh-dns`: Enable DNS-based service discovery
329
330use crate::service_mesh::{
331    RiServiceEndpoint, RiServiceMesh, RiServiceMeshConfig,
332    RiServiceDiscovery, RiServiceInstance,
333    RiHealthChecker, RiHealthStatus,
334    RiTrafficManager, RiTrafficRoute,
335};
336
337
338c_wrapper!(CRiServiceMesh, RiServiceMesh);
339c_wrapper!(CRiServiceMeshConfig, RiServiceMeshConfig);
340c_wrapper!(CRiServiceEndpoint, RiServiceEndpoint);
341
342// RiServiceMeshConfig constructors and destructors
343c_constructor!(
344    ri_service_mesh_config_new,
345    CRiServiceMeshConfig,
346    RiServiceMeshConfig,
347    RiServiceMeshConfig::default()
348);
349c_destructor!(ri_service_mesh_config_free, CRiServiceMeshConfig);
350
351// RiServiceMesh constructors and destructors
352#[no_mangle]
353pub extern "C" fn ri_service_mesh_new(config: *mut CRiServiceMeshConfig) -> *mut CRiServiceMesh {
354    if config.is_null() {
355        return std::ptr::null_mut();
356    }
357    unsafe {
358        let config = (*config).inner.clone();
359        match RiServiceMesh::new(config) {
360            Ok(mesh) => Box::into_raw(Box::new(CRiServiceMesh::new(mesh))),
361            Err(_) => std::ptr::null_mut(),
362        }
363    }
364}
365c_destructor!(ri_service_mesh_free, CRiServiceMesh);
366
367// RiServiceEndpoint constructors and destructors
368#[no_mangle]
369pub extern "C" fn ri_service_endpoint_new(
370    service_name: *const std::ffi::c_char,
371    endpoint: *const std::ffi::c_char,
372    weight: u32,
373) -> *mut CRiServiceEndpoint {
374    if service_name.is_null() || endpoint.is_null() {
375        return std::ptr::null_mut();
376    }
377    unsafe {
378        let service_name_str = match std::ffi::CStr::from_ptr(service_name).to_str() {
379            Ok(s) => s.to_string(),
380            Err(_) => return std::ptr::null_mut(),
381        };
382        let endpoint_str = match std::ffi::CStr::from_ptr(endpoint).to_str() {
383            Ok(s) => s.to_string(),
384            Err(_) => return std::ptr::null_mut(),
385        };
386        let ep = RiServiceEndpoint {
387            service_name: service_name_str,
388            endpoint: endpoint_str,
389            weight,
390            metadata: std::collections::HashMap::default(),
391            health_status: crate::service_mesh::RiServiceHealthStatus::Unknown,
392            last_health_check: std::time::SystemTime::now(),
393        };
394        Box::into_raw(Box::new(CRiServiceEndpoint::new(ep)))
395    }
396}
397c_destructor!(ri_service_endpoint_free, CRiServiceEndpoint);
398
399// RiServiceEndpoint getters
400c_string_getter!(
401    ri_service_endpoint_get_service_name,
402    CRiServiceEndpoint,
403    |inner: &RiServiceEndpoint| inner.service_name.clone()
404);
405c_string_getter!(
406    ri_service_endpoint_get_endpoint,
407    CRiServiceEndpoint,
408    |inner: &RiServiceEndpoint| inner.endpoint.clone()
409);
410
411#[no_mangle]
412pub extern "C" fn ri_service_endpoint_get_weight(obj: *mut CRiServiceEndpoint) -> u32 {
413    if obj.is_null() {
414        return 0;
415    }
416    unsafe { (*obj).inner.weight }
417}
418
419#[no_mangle]
420pub extern "C" fn ri_service_endpoint_get_health_status(obj: *mut CRiServiceEndpoint) -> std::ffi::c_int {
421    if obj.is_null() {
422        return -1;
423    }
424    unsafe {
425        match (*obj).inner.health_status {
426            crate::service_mesh::RiServiceHealthStatus::Healthy => 0,
427            crate::service_mesh::RiServiceHealthStatus::Unhealthy => 1,
428            crate::service_mesh::RiServiceHealthStatus::Unknown => 2,
429        }
430    }
431}
432
433// RiServiceMesh functions
434#[no_mangle]
435pub extern "C" fn ri_service_mesh_register(
436    mesh: *mut CRiServiceMesh,
437    endpoint: *mut CRiServiceEndpoint,
438) -> std::ffi::c_int {
439    if mesh.is_null() || endpoint.is_null() {
440        return -1;
441    }
442    let rt = match tokio::runtime::Runtime::new() {
443        Ok(rt) => rt,
444        Err(_) => return -2,
445    };
446    unsafe {
447        let ep = (*endpoint).inner.clone();
448        rt.block_on(async {
449            match (*mesh).inner.register_service(&ep.service_name, &ep.endpoint, ep.weight, None).await {
450                Ok(_) => 0,
451                Err(_) => -3,
452            }
453        })
454    }
455}
456
457#[no_mangle]
458pub extern "C" fn ri_service_mesh_deregister(
459    mesh: *mut CRiServiceMesh,
460    service_name: *const std::ffi::c_char,
461    endpoint: *const std::ffi::c_char,
462) -> std::ffi::c_int {
463    if mesh.is_null() || service_name.is_null() || endpoint.is_null() {
464        return -1;
465    }
466    let rt = match tokio::runtime::Runtime::new() {
467        Ok(rt) => rt,
468        Err(_) => return -2,
469    };
470    unsafe {
471        let service_name_str = match std::ffi::CStr::from_ptr(service_name).to_str() {
472            Ok(s) => s,
473            Err(_) => return -3,
474        };
475        let endpoint_str = match std::ffi::CStr::from_ptr(endpoint).to_str() {
476            Ok(s) => s,
477            Err(_) => return -3,
478        };
479        rt.block_on(async {
480            match (*mesh).inner.unregister_service(service_name_str, endpoint_str).await {
481                Ok(_) => 0,
482                Err(_) => -4,
483            }
484        })
485    }
486}
487
488#[no_mangle]
489pub extern "C" fn ri_service_mesh_discover(
490    mesh: *mut CRiServiceMesh,
491    service_name: *const std::ffi::c_char,
492    out_endpoints: *mut *mut CRiServiceEndpoint,
493    out_count: *mut usize,
494) -> std::ffi::c_int {
495    if mesh.is_null() || service_name.is_null() || out_endpoints.is_null() || out_count.is_null() {
496        return -1;
497    }
498    let rt = match tokio::runtime::Runtime::new() {
499        Ok(rt) => rt,
500        Err(_) => return -2,
501    };
502    unsafe {
503        let service_name_str = match std::ffi::CStr::from_ptr(service_name).to_str() {
504            Ok(s) => s,
505            Err(_) => return -3,
506        };
507        match rt.block_on(async { (*mesh).inner.discover_service(service_name_str).await }) {
508            Ok(endpoints) => {
509                let count = endpoints.len();
510                *out_count = count;
511                if count == 0 {
512                    *out_endpoints = std::ptr::null_mut();
513                    return 0;
514                }
515                let ptr = Box::into_raw(Box::new(Vec::with_capacity(count)));
516                (*ptr).extend(endpoints.into_iter().map(CRiServiceEndpoint::new));
517                *out_endpoints = ptr as *mut CRiServiceEndpoint;
518                0
519            }
520            Err(_) => -4,
521        }
522    }
523}
524
525#[no_mangle]
526pub extern "C" fn ri_service_mesh_get_healthy_count(
527    mesh: *mut CRiServiceMesh,
528    service_name: *const std::ffi::c_char,
529) -> u32 {
530    if mesh.is_null() || service_name.is_null() {
531        return 0;
532    }
533    let rt = match tokio::runtime::Runtime::new() {
534        Ok(rt) => rt,
535        Err(_) => return 0,
536    };
537    unsafe {
538        let service_name_str = match std::ffi::CStr::from_ptr(service_name).to_str() {
539            Ok(s) => s,
540            Err(_) => return 0,
541        };
542        match rt.block_on(async { (*mesh).inner.discover_service(service_name_str).await }) {
543            Ok(endpoints) => endpoints.len() as u32,
544            Err(_) => 0,
545        }
546    }
547}
548
549#[no_mangle]
550pub extern "C" fn ri_service_mesh_get_stats(
551    mesh: *mut CRiServiceMesh,
552    out_total_services: *mut usize,
553    out_total_endpoints: *mut usize,
554    out_healthy_endpoints: *mut usize,
555    out_unhealthy_endpoints: *mut usize,
556) -> std::ffi::c_int {
557    if mesh.is_null() {
558        return -1;
559    }
560    let rt = match tokio::runtime::Runtime::new() {
561        Ok(rt) => rt,
562        Err(_) => return -2,
563    };
564    unsafe {
565        let stats = rt.block_on(async { (*mesh).inner.get_stats().await });
566        if !out_total_services.is_null() {
567            *out_total_services = stats.total_services;
568        }
569        if !out_total_endpoints.is_null() {
570            *out_total_endpoints = stats.total_endpoints;
571        }
572        if !out_healthy_endpoints.is_null() {
573            *out_healthy_endpoints = stats.healthy_endpoints;
574        }
575        if !out_unhealthy_endpoints.is_null() {
576            *out_unhealthy_endpoints = stats.unhealthy_endpoints;
577        }
578        0
579    }
580}
581
582// RiServiceDiscovery C bindings
583c_wrapper!(CRiServiceDiscovery, RiServiceDiscovery);
584
585#[no_mangle]
586pub extern "C" fn ri_service_discovery_new(enabled: bool) -> *mut CRiServiceDiscovery {
587    Box::into_raw(Box::new(CRiServiceDiscovery::new(RiServiceDiscovery::new(enabled))))
588}
589c_destructor!(ri_service_discovery_free, CRiServiceDiscovery);
590
591#[no_mangle]
592pub extern "C" fn ri_service_discovery_register(
593    discovery: *mut CRiServiceDiscovery,
594    service_name: *const std::ffi::c_char,
595    host: *const std::ffi::c_char,
596    port: u16,
597) -> *mut std::ffi::c_char {
598    if discovery.is_null() || service_name.is_null() || host.is_null() {
599        return std::ptr::null_mut();
600    }
601    let rt = match tokio::runtime::Runtime::new() {
602        Ok(rt) => rt,
603        Err(_) => return std::ptr::null_mut(),
604    };
605    unsafe {
606        let service_name_str = match std::ffi::CStr::from_ptr(service_name).to_str() {
607            Ok(s) => s,
608            Err(_) => return std::ptr::null_mut(),
609        };
610        let host_str = match std::ffi::CStr::from_ptr(host).to_str() {
611            Ok(s) => s,
612            Err(_) => return std::ptr::null_mut(),
613        };
614        match rt.block_on(async {
615            (*discovery).inner.register_service(service_name_str, host_str, port, std::collections::HashMap::default()).await
616        }) {
617            Ok(instance_id) => match std::ffi::CString::new(instance_id) {
618                Ok(c_str) => c_str.into_raw(),
619                Err(_) => std::ptr::null_mut(),
620            },
621            Err(_) => std::ptr::null_mut(),
622        }
623    }
624}
625
626#[no_mangle]
627pub extern "C" fn ri_service_discovery_deregister(
628    discovery: *mut CRiServiceDiscovery,
629    instance_id: *const std::ffi::c_char,
630) -> std::ffi::c_int {
631    if discovery.is_null() || instance_id.is_null() {
632        return -1;
633    }
634    let rt = match tokio::runtime::Runtime::new() {
635        Ok(rt) => rt,
636        Err(_) => return -2,
637    };
638    unsafe {
639        let instance_id_str = match std::ffi::CStr::from_ptr(instance_id).to_str() {
640            Ok(s) => s,
641            Err(_) => return -3,
642        };
643        match rt.block_on(async { (*discovery).inner.deregister_service(instance_id_str).await }) {
644            Ok(_) => 0,
645            Err(_) => -4,
646        }
647    }
648}
649
650#[no_mangle]
651pub extern "C" fn ri_service_discovery_discover(
652    discovery: *mut CRiServiceDiscovery,
653    service_name: *const std::ffi::c_char,
654    out_instances: *mut *mut CRiServiceInstance,
655    out_count: *mut usize,
656) -> std::ffi::c_int {
657    if discovery.is_null() || service_name.is_null() || out_instances.is_null() || out_count.is_null() {
658        return -1;
659    }
660    let rt = match tokio::runtime::Runtime::new() {
661        Ok(rt) => rt,
662        Err(_) => return -2,
663    };
664    unsafe {
665        let service_name_str = match std::ffi::CStr::from_ptr(service_name).to_str() {
666            Ok(s) => s,
667            Err(_) => return -3,
668        };
669        match rt.block_on(async { (*discovery).inner.discover_service(service_name_str).await }) {
670            Ok(instances) => {
671                let count = instances.len();
672                *out_count = count;
673                if count == 0 {
674                    *out_instances = std::ptr::null_mut();
675                    return 0;
676                }
677                let ptr = Box::into_raw(Box::new(Vec::with_capacity(count)));
678                (*ptr).extend(instances.into_iter().map(CRiServiceInstance::new));
679                *out_instances = ptr as *mut CRiServiceInstance;
680                0
681            }
682            Err(_) => -4,
683        }
684    }
685}
686
687// RiServiceInstance C bindings
688c_wrapper!(CRiServiceInstance, RiServiceInstance);
689
690c_string_getter!(
691    ri_service_instance_get_id,
692    CRiServiceInstance,
693    |inner: &RiServiceInstance| inner.id.clone()
694);
695c_string_getter!(
696    ri_service_instance_get_service_name,
697    CRiServiceInstance,
698    |inner: &RiServiceInstance| inner.service_name.clone()
699);
700c_string_getter!(
701    ri_service_instance_get_host,
702    CRiServiceInstance,
703    |inner: &RiServiceInstance| inner.host.clone()
704);
705
706#[no_mangle]
707pub extern "C" fn ri_service_instance_get_port(obj: *mut CRiServiceInstance) -> u16 {
708    if obj.is_null() {
709        return 0;
710    }
711    unsafe { (*obj).inner.port }
712}
713
714#[no_mangle]
715pub extern "C" fn ri_service_instance_get_status(obj: *mut CRiServiceInstance) -> std::ffi::c_int {
716    if obj.is_null() {
717        return -1;
718    }
719    unsafe {
720        match (*obj).inner.status {
721            crate::service_mesh::RiServiceStatus::Starting => 0,
722            crate::service_mesh::RiServiceStatus::Running => 1,
723            crate::service_mesh::RiServiceStatus::Stopping => 2,
724            crate::service_mesh::RiServiceStatus::Stopped => 3,
725            crate::service_mesh::RiServiceStatus::Unhealthy => 4,
726        }
727    }
728}
729
730c_destructor!(ri_service_instance_free, CRiServiceInstance);
731
732// RiHealthChecker C bindings
733c_wrapper!(CRiHealthChecker, RiHealthChecker);
734
735#[no_mangle]
736pub extern "C" fn ri_health_checker_new(check_interval_secs: u64) -> *mut CRiHealthChecker {
737    Box::into_raw(Box::new(CRiHealthChecker::new(RiHealthChecker::new(std::time::Duration::from_secs(check_interval_secs)))))
738}
739c_destructor!(ri_health_checker_free, CRiHealthChecker);
740
741#[no_mangle]
742pub extern "C" fn ri_health_checker_start(
743    checker: *mut CRiHealthChecker,
744    service_name: *const std::ffi::c_char,
745    endpoint: *const std::ffi::c_char,
746) -> std::ffi::c_int {
747    if checker.is_null() || service_name.is_null() || endpoint.is_null() {
748        return -1;
749    }
750    let rt = match tokio::runtime::Runtime::new() {
751        Ok(rt) => rt,
752        Err(_) => return -2,
753    };
754    unsafe {
755        let service_name_str = match std::ffi::CStr::from_ptr(service_name).to_str() {
756            Ok(s) => s,
757            Err(_) => return -3,
758        };
759        let endpoint_str = match std::ffi::CStr::from_ptr(endpoint).to_str() {
760            Ok(s) => s,
761            Err(_) => return -3,
762        };
763        match rt.block_on(async { (*checker).inner.start_health_check(service_name_str, endpoint_str).await }) {
764            Ok(_) => 0,
765            Err(_) => -4,
766        }
767    }
768}
769
770#[no_mangle]
771pub extern "C" fn ri_health_checker_stop(
772    checker: *mut CRiHealthChecker,
773    service_name: *const std::ffi::c_char,
774    endpoint: *const std::ffi::c_char,
775) -> std::ffi::c_int {
776    if checker.is_null() || service_name.is_null() || endpoint.is_null() {
777        return -1;
778    }
779    let rt = match tokio::runtime::Runtime::new() {
780        Ok(rt) => rt,
781        Err(_) => return -2,
782    };
783    unsafe {
784        let service_name_str = match std::ffi::CStr::from_ptr(service_name).to_str() {
785            Ok(s) => s,
786            Err(_) => return -3,
787        };
788        let endpoint_str = match std::ffi::CStr::from_ptr(endpoint).to_str() {
789            Ok(s) => s,
790            Err(_) => return -3,
791        };
792        match rt.block_on(async { (*checker).inner.stop_health_check(service_name_str, endpoint_str).await }) {
793            Ok(_) => 0,
794            Err(_) => -4,
795        }
796    }
797}
798
799#[no_mangle]
800pub extern "C" fn ri_health_checker_get_summary(
801    checker: *mut CRiHealthChecker,
802    service_name: *const std::ffi::c_char,
803    out_healthy: *mut bool,
804    out_success_rate: *mut f64,
805    out_avg_response_ms: *mut u64,
806) -> std::ffi::c_int {
807    if checker.is_null() || service_name.is_null() {
808        return -1;
809    }
810    let rt = match tokio::runtime::Runtime::new() {
811        Ok(rt) => rt,
812        Err(_) => return -2,
813    };
814    unsafe {
815        let service_name_str = match std::ffi::CStr::from_ptr(service_name).to_str() {
816            Ok(s) => s,
817            Err(_) => return -3,
818        };
819        match rt.block_on(async { (*checker).inner.get_service_health_summary(service_name_str).await }) {
820            Ok(summary) => {
821                if !out_healthy.is_null() {
822                    *out_healthy = matches!(summary.overall_status, RiHealthStatus::Healthy);
823                }
824                if !out_success_rate.is_null() {
825                    *out_success_rate = summary.success_rate;
826                }
827                if !out_avg_response_ms.is_null() {
828                    *out_avg_response_ms = summary.average_response_time.as_millis() as u64;
829                }
830                0
831            }
832            Err(_) => -4,
833        }
834    }
835}
836
837// RiTrafficManager C bindings
838c_wrapper!(CRiTrafficManager, RiTrafficManager);
839
840#[no_mangle]
841pub extern "C" fn ri_traffic_manager_new(enabled: bool) -> *mut CRiTrafficManager {
842    Box::into_raw(Box::new(CRiTrafficManager::new(RiTrafficManager::new(enabled))))
843}
844c_destructor!(ri_traffic_manager_free, CRiTrafficManager);
845
846#[no_mangle]
847pub extern "C" fn ri_traffic_manager_add_route(
848    manager: *mut CRiTrafficManager,
849    route: *mut CRiTrafficRoute,
850) -> std::ffi::c_int {
851    if manager.is_null() || route.is_null() {
852        return -1;
853    }
854    let rt = match tokio::runtime::Runtime::new() {
855        Ok(rt) => rt,
856        Err(_) => return -2,
857    };
858    unsafe {
859        match rt.block_on(async { (*manager).inner.add_traffic_route((*route).inner.clone()).await }) {
860            Ok(_) => 0,
861            Err(_) => -3,
862        }
863    }
864}
865
866#[no_mangle]
867pub extern "C" fn ri_traffic_manager_remove_route(
868    manager: *mut CRiTrafficManager,
869    source_service: *const std::ffi::c_char,
870    route_name: *const std::ffi::c_char,
871) -> std::ffi::c_int {
872    if manager.is_null() || source_service.is_null() || route_name.is_null() {
873        return -1;
874    }
875    let rt = match tokio::runtime::Runtime::new() {
876        Ok(rt) => rt,
877        Err(_) => return -2,
878    };
879    unsafe {
880        let source_service_str = match std::ffi::CStr::from_ptr(source_service).to_str() {
881            Ok(s) => s,
882            Err(_) => return -3,
883        };
884        let route_name_str = match std::ffi::CStr::from_ptr(route_name).to_str() {
885            Ok(s) => s,
886            Err(_) => return -3,
887        };
888        match rt.block_on(async { (*manager).inner.remove_traffic_route(source_service_str, route_name_str).await }) {
889            Ok(_) => 0,
890            Err(_) => -4,
891        }
892    }
893}
894
895#[no_mangle]
896pub extern "C" fn ri_traffic_manager_set_circuit_breaker(
897    manager: *mut CRiTrafficManager,
898    service: *const std::ffi::c_char,
899    consecutive_errors: u32,
900    max_ejection_percent: f64,
901) -> std::ffi::c_int {
902    if manager.is_null() || service.is_null() {
903        return -1;
904    }
905    let rt = match tokio::runtime::Runtime::new() {
906        Ok(rt) => rt,
907        Err(_) => return -2,
908    };
909    unsafe {
910        let service_str = match std::ffi::CStr::from_ptr(service).to_str() {
911            Ok(s) => s,
912            Err(_) => return -3,
913        };
914        let config = crate::service_mesh::traffic_management::RiCircuitBreakerConfig {
915            consecutive_errors,
916            interval: std::time::Duration::from_secs(10),
917            base_ejection_time: std::time::Duration::from_secs(30),
918            max_ejection_percent,
919        };
920        match rt.block_on(async { (*manager).inner.set_circuit_breaker_config(service_str, config).await }) {
921            Ok(_) => 0,
922            Err(_) => -4,
923        }
924    }
925}
926
927#[no_mangle]
928pub extern "C" fn ri_traffic_manager_set_rate_limit(
929    manager: *mut CRiTrafficManager,
930    service: *const std::ffi::c_char,
931    requests_per_second: u32,
932    burst_size: u32,
933) -> std::ffi::c_int {
934    if manager.is_null() || service.is_null() {
935        return -1;
936    }
937    let rt = match tokio::runtime::Runtime::new() {
938        Ok(rt) => rt,
939        Err(_) => return -2,
940    };
941    unsafe {
942        let service_str = match std::ffi::CStr::from_ptr(service).to_str() {
943            Ok(s) => s,
944            Err(_) => return -3,
945        };
946        let config = crate::service_mesh::traffic_management::RiRateLimitConfig {
947            requests_per_second,
948            burst_size,
949            window: std::time::Duration::from_secs(1),
950        };
951        match rt.block_on(async { (*manager).inner.set_rate_limit_config(service_str, config).await }) {
952            Ok(_) => 0,
953            Err(_) => -4,
954        }
955    }
956}
957
958// RiTrafficRoute C bindings
959c_wrapper!(CRiTrafficRoute, RiTrafficRoute);
960
961#[no_mangle]
962pub extern "C" fn ri_traffic_route_new(
963    name: *const std::ffi::c_char,
964    source_service: *const std::ffi::c_char,
965    destination_service: *const std::ffi::c_char,
966) -> *mut CRiTrafficRoute {
967    if name.is_null() || source_service.is_null() || destination_service.is_null() {
968        return std::ptr::null_mut();
969    }
970    unsafe {
971        let name_str = match std::ffi::CStr::from_ptr(name).to_str() {
972            Ok(s) => s.to_string(),
973            Err(_) => return std::ptr::null_mut(),
974        };
975        let source_str = match std::ffi::CStr::from_ptr(source_service).to_str() {
976            Ok(s) => s.to_string(),
977            Err(_) => return std::ptr::null_mut(),
978        };
979        let dest_str = match std::ffi::CStr::from_ptr(destination_service).to_str() {
980            Ok(s) => s.to_string(),
981            Err(_) => return std::ptr::null_mut(),
982        };
983        let route = RiTrafficRoute {
984            name: name_str,
985            source_service: source_str,
986            destination_service: dest_str,
987            match_criteria: crate::service_mesh::RiMatchCriteria {
988                path_prefix: None,
989                headers: std::collections::HashMap::default(),
990                method: None,
991                query_parameters: std::collections::HashMap::default(),
992            },
993            route_action: crate::service_mesh::RiRouteAction::Route(vec![]),
994            retry_policy: None,
995            timeout: None,
996            fault_injection: None,
997        };
998        Box::into_raw(Box::new(CRiTrafficRoute::new(route)))
999    }
1000}
1001c_destructor!(ri_traffic_route_free, CRiTrafficRoute);
1002
1003c_string_getter!(
1004    ri_traffic_route_get_name,
1005    CRiTrafficRoute,
1006    |inner: &RiTrafficRoute| inner.name.clone()
1007);
1008c_string_getter!(
1009    ri_traffic_route_get_source_service,
1010    CRiTrafficRoute,
1011    |inner: &RiTrafficRoute| inner.source_service.clone()
1012);
1013c_string_getter!(
1014    ri_traffic_route_get_destination_service,
1015    CRiTrafficRoute,
1016    |inner: &RiTrafficRoute| inner.destination_service.clone()
1017);