camel_component_http/
registry.rs1use std::collections::HashMap;
2use std::path::PathBuf;
3use std::sync::Arc;
4
5use camel_component_api::CamelError;
6use tokio::sync::{RwLock, mpsc};
7use tokio_util::sync::CancellationToken;
8use tower_http::services::ServeDir;
9
10use crate::RequestEnvelope;
11use crate::rest_match::RestEndpoint;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub enum MountMode {
17 Static,
18 Spa,
19}
20
21#[allow(dead_code)]
22pub struct StaticMount {
23 pub mount_path: String,
24 pub mode: MountMode,
25 pub dir: PathBuf,
26 pub cache_control: String,
27 pub error_pages: HashMap<u16, PathBuf>,
28 pub serve_dir: ServeDir,
29}
30
31impl std::fmt::Debug for StaticMount {
32 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33 f.debug_struct("StaticMount")
34 .field("mount_path", &self.mount_path)
35 .field("mode", &self.mode)
36 .field("dir", &self.dir)
37 .field("cache_control", &self.cache_control)
38 .field("error_pages", &self.error_pages)
39 .finish_non_exhaustive()
40 }
41}
42
43pub(crate) struct HttpRouteRegistryInner {
44 pub api_routes: HashMap<String, mpsc::Sender<RequestEnvelope>>,
47 pub rest_endpoints: Vec<RestEndpoint<mpsc::Sender<RequestEnvelope>>>,
52 pub mounts: Vec<StaticMount>,
53}
54
55impl std::fmt::Debug for HttpRouteRegistryInner {
56 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57 f.debug_struct("HttpRouteRegistryInner")
58 .field("api_routes", &self.api_routes.keys())
59 .field("rest_endpoints", &self.rest_endpoints.len())
60 .field("mounts", &self.mounts.len())
61 .finish()
62 }
63}
64
65#[derive(Clone)]
66pub struct HttpRouteRegistry {
67 pub(crate) inner: Arc<RwLock<HttpRouteRegistryInner>>,
68 pub(crate) server_exited: CancellationToken,
81}
82
83impl std::fmt::Debug for HttpRouteRegistry {
84 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85 f.debug_struct("HttpRouteRegistry").finish_non_exhaustive()
86 }
87}
88
89impl Default for HttpRouteRegistry {
90 fn default() -> Self {
91 Self::new()
92 }
93}
94
95impl HttpRouteRegistry {
96 pub fn new() -> Self {
97 Self::new_with_server_exited(CancellationToken::new())
98 }
99
100 pub(crate) fn new_with_server_exited(server_exited: CancellationToken) -> Self {
103 Self {
104 inner: Arc::new(RwLock::new(HttpRouteRegistryInner {
105 api_routes: HashMap::new(),
106 rest_endpoints: Vec::new(),
107 mounts: Vec::new(),
108 })),
109 server_exited,
110 }
111 }
112
113 pub async fn register_api_route(
114 &self,
115 path: String,
116 sender: mpsc::Sender<RequestEnvelope>,
117 ) -> Result<(), CamelError> {
118 let mut inner = self.inner.write().await;
119 if inner.api_routes.contains_key(&path) {
120 return Err(CamelError::Config(format!(
121 "duplicate HTTP consumer path '{path}' on this listener"
122 )));
123 }
124 inner.api_routes.insert(path, sender);
125 Ok(())
126 }
127
128 pub async fn unregister_api_route(&self, path: &str) {
129 let mut inner = self.inner.write().await;
130 inner.api_routes.remove(path);
131 }
132
133 pub async fn register_rest_endpoint(
137 &self,
138 method: String,
139 segments: Vec<crate::rest_match::PathSegment>,
140 sender: mpsc::Sender<RequestEnvelope>,
141 ) -> Result<(), CamelError> {
142 let mut inner = self.inner.write().await;
143 if inner
144 .rest_endpoints
145 .iter()
146 .any(|ep| ep.method == method && ep.segments == segments)
147 {
148 let template = segments
149 .iter()
150 .map(|segment| match segment {
151 crate::rest_match::PathSegment::Literal(value) => value.clone(),
152 crate::rest_match::PathSegment::Param(name) => format!("{{{name}}}"),
153 })
154 .collect::<Vec<_>>()
155 .join("/");
156 return Err(CamelError::Config(format!(
157 "duplicate HTTP consumer endpoint '{method} /{template}' on this listener"
158 )));
159 }
160 inner.rest_endpoints.push(RestEndpoint {
161 method,
162 segments,
163 payload: sender,
164 });
165 Ok(())
166 }
167
168 pub async fn unregister_rest_endpoint(&self, method: &str, path_template: &str) {
175 let target_segments = crate::rest_match::parse_path_template(path_template);
176 let mut inner = self.inner.write().await;
177 inner.rest_endpoints.retain(|ep| {
178 !(ep.method == method && ep.segments == target_segments)
181 });
182 }
183
184 #[allow(dead_code)]
192 pub async fn register_static_mount(&self, mount: StaticMount) -> Result<(), CamelError> {
193 let mut inner = self.inner.write().await;
194 if inner
195 .mounts
196 .iter()
197 .any(|m| m.mount_path == mount.mount_path)
198 {
199 return Err(CamelError::Config(format!(
200 "duplicate static mount path '{}' on this port",
201 mount.mount_path
202 )));
203 }
204 inner.mounts.push(mount);
205 Ok(())
206 }
207
208 #[allow(dead_code)]
210 pub async fn unregister_static_mount(&self, mount_path: &str) {
211 let mut inner = self.inner.write().await;
212 inner.mounts.retain(|m| m.mount_path != mount_path);
213 }
214}