assay_workflow/api/
mod.rs1pub mod activities;
2pub mod auth;
3pub mod dashboard;
4pub mod events;
5pub mod namespaces;
6pub mod openapi;
7pub mod queues;
8pub mod schedules;
9pub mod tasks;
10pub mod workers;
11pub mod workflow_tasks;
12pub mod workflows;
13
14use std::sync::Arc;
15
16use axum::middleware;
17use axum::Router;
18use tokio::sync::broadcast;
19use tracing::info;
20
21use crate::api::auth::AuthMode;
22use crate::engine::Engine;
23use crate::store::WorkflowStore;
24
25pub struct AppState<S: WorkflowStore> {
27 pub engine: Arc<Engine<S>>,
28 pub event_tx: broadcast::Sender<events::BroadcastEvent>,
29 pub auth_mode: AuthMode,
30}
31
32pub fn router<S: WorkflowStore + 'static>(state: Arc<AppState<S>>) -> Router {
34 let needs_auth = !matches!(state.auth_mode, AuthMode::NoAuth);
35
36 let api = Router::new()
37 .nest("/api/v1", api_v1_router())
38 .nest("/api/v1", events::router());
39
40 let api = if needs_auth {
41 api.layer(middleware::from_fn_with_state(
42 Arc::clone(&state),
43 auth::auth_middleware,
44 ))
45 } else {
46 api
47 };
48
49 let app = api
51 .merge(dashboard::router())
52 .merge(openapi::router());
53
54 app.with_state(state)
55}
56
57fn api_v1_router<S: WorkflowStore + 'static>() -> Router<Arc<AppState<S>>> {
58 Router::new()
59 .merge(workflows::router())
60 .merge(activities::router())
61 .merge(workflow_tasks::router())
62 .merge(tasks::router())
63 .merge(schedules::router())
64 .merge(workers::router())
65 .merge(namespaces::router())
66 .merge(queues::router())
67}
68
69pub async fn serve<S: WorkflowStore + 'static>(
71 engine: Engine<S>,
72 port: u16,
73 auth_mode: AuthMode,
74) -> anyhow::Result<()> {
75 let (event_tx, _) = broadcast::channel(1024);
76
77 let mode_desc = match &auth_mode {
78 AuthMode::NoAuth => "no-auth (open access)".to_string(),
79 AuthMode::ApiKey => "api-key".to_string(),
80 AuthMode::Jwt { issuer, .. } => format!("jwt (issuer: {issuer})"),
81 };
82
83 let state = Arc::new(AppState {
84 engine: Arc::new(engine),
85 event_tx,
86 auth_mode,
87 });
88
89 let app = router(state);
90 let listener = tokio::net::TcpListener::bind(format!("0.0.0.0:{port}")).await?;
91 info!("Workflow API listening on 0.0.0.0:{port} (auth: {mode_desc})");
92
93 axum::serve(listener, app).await?;
94 Ok(())
95}