Skip to content

Commit 42b48a8

Browse files
committed
Improve routing
1 parent 063f1ca commit 42b48a8

File tree

1 file changed

+32
-25
lines changed

1 file changed

+32
-25
lines changed

crates/common/src/integrations/registry.rs

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::collections::BTreeMap;
1+
use std::collections::{BTreeMap, HashMap};
22
use std::sync::Arc;
33

44
use async_trait::async_trait;
@@ -163,16 +163,13 @@ impl IntegrationRegistrationBuilder {
163163
}
164164
}
165165

166-
struct RegisteredRoute {
167-
method: Method,
168-
path: &'static str,
169-
proxy: Arc<dyn IntegrationProxy>,
170-
integration_id: &'static str,
171-
}
166+
type RouteKey = (Method, String);
167+
type RouteValue = (Arc<dyn IntegrationProxy>, &'static str);
172168

173169
#[derive(Default)]
174170
struct IntegrationRegistryInner {
175-
routes: Vec<RegisteredRoute>,
171+
route_map: HashMap<RouteKey, RouteValue>,
172+
routes: Vec<(IntegrationEndpoint, &'static str)>,
176173
html_rewriters: Vec<Arc<dyn IntegrationAttributeRewriter>>,
177174
script_rewriters: Vec<Arc<dyn IntegrationScriptRewriter>>,
178175
assets: Vec<(&'static str, String)>,
@@ -215,12 +212,20 @@ impl IntegrationRegistry {
215212
if let Some(registration) = builder(settings) {
216213
for proxy in registration.proxies {
217214
for route in proxy.routes() {
218-
inner.routes.push(RegisteredRoute {
219-
method: route.method.clone(),
220-
path: route.path,
221-
proxy: proxy.clone(),
222-
integration_id: registration.integration_id,
223-
});
215+
if inner
216+
.route_map
217+
.insert(
218+
(route.method.clone(), route.path.to_string()),
219+
(proxy.clone(), registration.integration_id),
220+
)
221+
.is_some()
222+
{
223+
panic!(
224+
"Integration route collision detected for {} {}",
225+
route.method, route.path
226+
);
227+
}
228+
inner.routes.push((route, registration.integration_id));
224229
}
225230
}
226231
inner
@@ -246,9 +251,8 @@ impl IntegrationRegistry {
246251
/// Return true when any proxy is registered for the provided route.
247252
pub fn has_route(&self, method: &Method, path: &str) -> bool {
248253
self.inner
249-
.routes
250-
.iter()
251-
.any(|r| r.method == method && r.path == path)
254+
.route_map
255+
.contains_key(&(method.clone(), path.to_string()))
252256
}
253257

254258
/// Dispatch a proxy request when an integration handles the path.
@@ -259,12 +263,15 @@ impl IntegrationRegistry {
259263
settings: &Settings,
260264
req: Request,
261265
) -> Option<Result<Response, Report<TrustedServerError>>> {
262-
for route in &self.inner.routes {
263-
if route.method == method && route.path == path {
264-
return Some(route.proxy.handle(settings, req).await);
265-
}
266+
if let Some((proxy, _)) = self
267+
.inner
268+
.route_map
269+
.get(&(method.clone(), path.to_string()))
270+
{
271+
Some(proxy.handle(settings, req).await)
272+
} else {
273+
None
266274
}
267-
None
268275
}
269276

270277
/// Give integrations a chance to rewrite HTML attributes.
@@ -302,10 +309,10 @@ impl IntegrationRegistry {
302309
pub fn registered_integrations(&self) -> Vec<IntegrationMetadata> {
303310
let mut map: BTreeMap<&'static str, IntegrationMetadata> = BTreeMap::new();
304311

305-
for route in &self.inner.routes {
312+
for (route, integration_id) in &self.inner.routes {
306313
let entry = map
307-
.entry(route.integration_id)
308-
.or_insert_with(|| IntegrationMetadata::new(route.integration_id));
314+
.entry(*integration_id)
315+
.or_insert_with(|| IntegrationMetadata::new(integration_id));
309316
entry
310317
.routes
311318
.push(IntegrationEndpoint::new(route.method.clone(), route.path));

0 commit comments

Comments
 (0)