camel_component_api/
component_context.rs1use std::sync::Arc;
2
3use camel_api::{AsyncHealthCheck, InFlightGauge, MetricsCollector, PlatformService};
4use camel_language_api::Language;
5use tokio_util::sync::CancellationToken;
6
7use crate::Component;
8
9pub trait ComponentContext: Send + Sync {
11 fn resolve_component(&self, scheme: &str) -> Option<Arc<dyn Component>>;
13
14 fn resolve_language(&self, name: &str) -> Option<Arc<dyn Language>>;
16
17 fn metrics(&self) -> Arc<dyn MetricsCollector>;
19
20 fn in_flight_counter(&self) -> Option<Arc<InFlightGauge>> {
26 None
27 }
28
29 fn component_metrics_enabled(&self) -> bool {
36 false
37 }
38
39 fn health(&self) -> Arc<dyn crate::HealthCheckRegistry> {
46 Arc::new(crate::NoOpHealthCheckRegistry)
47 }
48
49 fn shutdown_token(&self) -> Option<CancellationToken> {
59 None
60 }
61
62 fn platform_service(&self) -> Arc<dyn PlatformService>;
64
65 fn register_route_health_check(&self, route_id: &str, check: Arc<dyn AsyncHealthCheck>);
66
67 fn unregister_route_health_check(&self, route_id: &str);
68
69 fn route_id(&self) -> Option<&str> {
70 None
71 }
72
73 fn register_current_route_health_check(&self, check: Arc<dyn AsyncHealthCheck>) {
74 if let Some(id) = self.route_id() {
75 self.register_route_health_check(id, check);
76 }
77 }
78}
79
80pub struct NoOpComponentContext;
82
83impl ComponentContext for NoOpComponentContext {
84 fn resolve_component(&self, _scheme: &str) -> Option<Arc<dyn Component>> {
85 None
86 }
87
88 fn resolve_language(&self, _name: &str) -> Option<Arc<dyn Language>> {
89 None
90 }
91
92 fn metrics(&self) -> Arc<dyn MetricsCollector> {
93 Arc::new(camel_api::NoOpMetrics)
94 }
95
96 fn platform_service(&self) -> Arc<dyn PlatformService> {
97 Arc::new(camel_api::NoopPlatformService::default())
98 }
99
100 fn register_route_health_check(&self, _route_id: &str, _check: Arc<dyn AsyncHealthCheck>) {}
101
102 fn unregister_route_health_check(&self, _route_id: &str) {}
103}
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108
109 #[test]
110 fn component_context_health_default_is_noop() {
111 let ctx = NoOpComponentContext;
112 let h = ctx.health();
113 h.force_unhealthy_for_route("any", "any", "any");
115 }
116
117 #[test]
118 fn shutdown_token_default_is_none() {
119 let ctx = NoOpComponentContext;
120 assert!(
121 ctx.shutdown_token().is_none(),
122 "unbound contexts must return None so callers mint a local root"
123 );
124 }
125}