1use axum::extract::FromRef;
6use ironflow_auth::jwt::JwtConfig;
7use ironflow_engine::engine::Engine;
8use ironflow_store::entities::Run;
9use ironflow_store::store::RunStore;
10use ironflow_store::user_store::UserStore;
11use std::sync::Arc;
12use uuid::Uuid;
13
14use crate::error::ApiError;
15
16#[derive(Clone)]
47pub struct AppState {
48 pub store: Arc<dyn RunStore>,
50 pub user_store: Arc<dyn UserStore>,
52 pub engine: Arc<Engine>,
54 pub jwt_config: Arc<JwtConfig>,
56 pub worker_token: String,
58}
59
60impl FromRef<AppState> for Arc<dyn RunStore> {
61 fn from_ref(state: &AppState) -> Self {
62 Arc::clone(&state.store)
63 }
64}
65
66impl FromRef<AppState> for Arc<dyn UserStore> {
67 fn from_ref(state: &AppState) -> Self {
68 Arc::clone(&state.user_store)
69 }
70}
71
72impl FromRef<AppState> for Arc<JwtConfig> {
73 fn from_ref(state: &AppState) -> Self {
74 Arc::clone(&state.jwt_config)
75 }
76}
77
78impl AppState {
79 pub async fn get_run_or_404(&self, id: Uuid) -> Result<Run, ApiError> {
86 self.store
87 .get_run(id)
88 .await
89 .map_err(ApiError::from)?
90 .ok_or(ApiError::RunNotFound(id))
91 }
92}
93
94#[cfg(test)]
95mod tests {
96 use super::*;
97 use ironflow_core::providers::claude::ClaudeCodeProvider;
98 use ironflow_store::memory::InMemoryStore;
99
100 fn test_state() -> AppState {
101 let store = Arc::new(InMemoryStore::new());
102 let user_store = Arc::new(InMemoryStore::new());
103 let provider = Arc::new(ClaudeCodeProvider::new());
104 let engine = Arc::new(Engine::new(store.clone(), provider));
105 let jwt_config = Arc::new(JwtConfig {
106 secret: "test-secret".to_string(),
107 access_token_ttl_secs: 900,
108 refresh_token_ttl_secs: 604800,
109 cookie_domain: None,
110 cookie_secure: false,
111 });
112 AppState {
113 store,
114 user_store,
115 engine,
116 jwt_config,
117 worker_token: "test-worker-token".to_string(),
118 }
119 }
120
121 #[test]
122 fn app_state_cloneable() {
123 let state = test_state();
124 let _cloned = state.clone();
125 }
126
127 #[test]
128 fn app_state_from_ref() {
129 let state = test_state();
130 let extracted: Arc<dyn RunStore> = Arc::from_ref(&state);
131 assert!(Arc::ptr_eq(&extracted, &state.store));
132 }
133}