Skip to content

Commit 847d1e5

Browse files
committed
refactor(gateway): introduce SourcePlugin trait for uniform source dispatch
Eliminates the per-source iteration repeated between `http.rs::mount_sources` and `streams.rs::provision` by introducing a gateway-internal `SourcePlugin` trait. Each webhook source has a unit-struct plugin (GithubPlugin, SlackPlugin, ..., MicrosoftGraphPlugin) that owns both its JetStream provisioning loop and its HTTP route mounting loop, including any per-source edge cases. Two dispatch entry points -- `provision_webhook_sources` and `mount_webhook_sources` -- replace the repeated source-by-source dispatch blocks. Adding a new webhook source now touches one file (source_plugin.rs) instead of two. SlackPlugin's `mount` skips socket-mode-only integrations (no webhook config) since their HTTP route would never receive traffic; the runner is spawned in main.rs. Discord is intentionally excluded from `SourcePlugin` because its primary path is a WebSocket gateway runner, not a webhook receiver -- streams.rs still provisions it inline. All 579 gateway tests pass; full workspace tests pass. Signed-off-by: Erik Nilsen <enilsen16@live.com>
1 parent f2aa6ef commit 847d1e5

4 files changed

Lines changed: 489 additions & 197 deletions

File tree

rsworkspace/crates/trogon-gateway/src/http.rs

Lines changed: 4 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
use axum::Router;
2-
use tracing::info;
32
use trogon_nats::jetstream::{ClaimCheckPublisher, JetStreamPublisher, ObjectStorePut};
43

5-
use crate::config::{ResolvedConfig, SourceIntegration};
4+
use crate::config::ResolvedConfig;
5+
use crate::source_plugin;
66

77
pub(crate) fn mount_sources<P, S>(config: ResolvedConfig, publisher: ClaimCheckPublisher<P, S>) -> Router
88
where
99
P: JetStreamPublisher,
1010
S: ObjectStorePut,
1111
{
12-
let mut app = Router::new()
12+
let app = Router::new()
1313
.route(
1414
"/-/liveness",
1515
axum::routing::get(|| async { axum::http::StatusCode::OK }),
@@ -19,119 +19,7 @@ where
1919
axum::routing::get(|| async { axum::http::StatusCode::OK }),
2020
);
2121

22-
app = mount_webhook_integrations(
23-
app,
24-
"github",
25-
"/sources/github",
26-
&config.github,
27-
publisher.clone(),
28-
|p, cfg| crate::source::github::router(p, cfg),
29-
);
30-
for integration in &config.slack {
31-
if integration.config.webhook().is_none() {
32-
continue;
33-
}
34-
let path = format!("/sources/slack/{}", integration.id);
35-
app = app.nest(
36-
&path,
37-
crate::source::slack::router(publisher.clone(), &integration.config),
38-
);
39-
let integration_id = integration.id.as_str();
40-
info!(
41-
source = "slack",
42-
integration = integration_id,
43-
path,
44-
"mounted source integration"
45-
);
46-
}
47-
app = mount_webhook_integrations(
48-
app,
49-
"telegram",
50-
"/sources/telegram",
51-
&config.telegram,
52-
publisher.clone(),
53-
|p, cfg| crate::source::telegram::router(p, cfg),
54-
);
55-
app = mount_webhook_integrations(
56-
app,
57-
"twitter",
58-
"/sources/twitter",
59-
&config.twitter,
60-
publisher.clone(),
61-
|p, cfg| crate::source::twitter::router(p, cfg),
62-
);
63-
app = mount_webhook_integrations(
64-
app,
65-
"gitlab",
66-
"/sources/gitlab",
67-
&config.gitlab,
68-
publisher.clone(),
69-
|p, cfg| crate::source::gitlab::router(p, cfg),
70-
);
71-
app = mount_webhook_integrations(
72-
app,
73-
"incidentio",
74-
"/sources/incidentio",
75-
&config.incidentio,
76-
publisher.clone(),
77-
|p, cfg| crate::source::incidentio::router(p, cfg),
78-
);
79-
app = mount_webhook_integrations(
80-
app,
81-
"linear",
82-
"/sources/linear",
83-
&config.linear,
84-
publisher.clone(),
85-
|p, cfg| crate::source::linear::router(p, cfg),
86-
);
87-
app = mount_webhook_integrations(
88-
app,
89-
"microsoft-graph",
90-
"/sources/microsoft-graph",
91-
&config.microsoft_graph,
92-
publisher.clone(),
93-
|p, cfg| crate::source::microsoft_graph::router(p, cfg),
94-
);
95-
app = mount_webhook_integrations(
96-
app,
97-
"notion",
98-
"/sources/notion",
99-
&config.notion,
100-
publisher.clone(),
101-
|p, cfg| crate::source::notion::router(p, cfg),
102-
);
103-
app = mount_webhook_integrations(app, "sentry", "/sources/sentry", &config.sentry, publisher, |p, cfg| {
104-
crate::source::sentry::router(p, cfg)
105-
});
106-
107-
app
108-
}
109-
110-
fn mount_webhook_integrations<P, S, C, F>(
111-
mut app: Router,
112-
source: &'static str,
113-
source_path: &'static str,
114-
integrations: &[SourceIntegration<C>],
115-
publisher: ClaimCheckPublisher<P, S>,
116-
router: F,
117-
) -> Router
118-
where
119-
P: JetStreamPublisher,
120-
S: ObjectStorePut,
121-
F: Fn(ClaimCheckPublisher<P, S>, &C) -> Router,
122-
{
123-
for integration in integrations {
124-
let path = format!("{}/{}", source_path, integration.id);
125-
app = app.nest(&path, router(publisher.clone(), &integration.config));
126-
info!(
127-
source,
128-
integration = integration.id.as_str(),
129-
path,
130-
"mounted source integration"
131-
);
132-
}
133-
134-
app
22+
source_plugin::mount_webhook_sources(app, publisher, &config)
13523
}
13624

13725
#[cfg(test)]

rsworkspace/crates/trogon-gateway/src/main.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ mod source;
1111
#[cfg_attr(coverage, allow(dead_code))]
1212
mod source_integration_id;
1313
#[cfg_attr(coverage, allow(dead_code))]
14+
mod source_plugin;
15+
#[cfg_attr(coverage, allow(dead_code))]
1416
mod source_status;
1517
#[cfg_attr(coverage, allow(dead_code))]
1618
mod streams;

0 commit comments

Comments
 (0)