1use super::responses::*;
6use crate::routing::{Router, Route};
7use crate::providers::{ProviderError, ProviderRegistry, EventRegistry};
8use axum::{
9 extract::{Path, Query, State},
10 http::StatusCode,
11 response::Json,
12};
13use serde::Deserialize;
14use std::collections::HashMap;
15use std::sync::Arc;
16use std::time::{SystemTime, Instant};
17
18#[derive(Clone)]
20pub struct AppState {
21 pub router: Arc<Router>,
22 pub registry: Arc<ProviderRegistry>,
23 pub event_registry: Arc<EventRegistry>,
24 pub start_time: SystemTime,
25}
26
27#[derive(Debug, Deserialize)]
29pub struct ExecuteQuery {
30 #[serde(flatten)]
32 pub args: HashMap<String, serde_json::Value>,
33}
34
35#[derive(Debug, Deserialize)]
37pub struct ExecuteRequest {
38 #[serde(default)]
40 pub args: HashMap<String, serde_json::Value>,
41}
42
43#[derive(Debug, Deserialize)]
45pub struct ExecActionRequest {
46 pub provider: String,
48 pub feature: String,
50 pub operation: String,
52 #[serde(default)]
54 pub args: HashMap<String, serde_json::Value>,
55}
56
57pub async fn health(State(state): State<AppState>) -> Json<ApiResponse<HealthStatus>> {
60 let uptime = state.start_time.elapsed()
61 .unwrap_or_default()
62 .as_secs();
63
64 let stats = state.registry.get_statistics().await;
65
66 let health = HealthStatus {
67 status: "healthy".to_string(),
68 version: env!("CARGO_PKG_VERSION").to_string(),
69 uptime_seconds: uptime,
70 providers_loaded: stats.total_providers,
71 total_features: stats.total_features,
72 total_operations: stats.total_operations,
73 memory_usage_mb: get_memory_usage_mb(),
74 };
75
76 Json(ApiResponse::success(health))
77}
78
79pub async fn discover_providers(State(state): State<AppState>) -> Json<ApiResponse<DiscoveryResponse>> {
82 let metadata_list = state.registry.list_metadata().await;
83
84 let providers: Vec<ProviderSummary> = metadata_list
85 .into_iter()
86 .map(|metadata| ProviderSummary {
87 name: metadata.name,
88 version: metadata.version,
89 description: metadata.description,
90 features: metadata.features
91 .into_iter()
92 .map(|feature| FeatureSummary {
93 name: feature.name,
94 description: feature.description,
95 operations: feature.operations
96 .into_iter()
97 .map(|op| op.name)
98 .collect(),
99 })
100 .collect(),
101 })
102 .collect();
103
104 let total_features = providers.iter().map(|p| p.features.len()).sum();
105 let total_operations = providers.iter()
106 .flat_map(|p| &p.features)
107 .map(|f| f.operations.len())
108 .sum();
109
110 let discovery = DiscoveryResponse {
111 total_providers: providers.len(),
112 total_features,
113 total_operations,
114 providers,
115 };
116
117 Json(ApiResponse::success(discovery))
118}
119
120pub async fn get_provider(
123 Path(provider): Path<String>,
124 State(state): State<AppState>,
125) -> Result<Json<ApiResponse<ProviderInfo>>, StatusCode> {
126 match state.registry.get_metadata(&provider).await {
127 Some(metadata) => Ok(Json(ApiResponse::success(metadata.into()))),
128 None => Err(StatusCode::NOT_FOUND),
129 }
130}
131
132pub async fn get_feature(
135 Path((provider, feature)): Path<(String, String)>,
136 State(state): State<AppState>,
137) -> Result<Json<ApiResponse<FeatureInfo>>, StatusCode> {
138 let metadata = state.registry.get_metadata(&provider).await
139 .ok_or(StatusCode::NOT_FOUND)?;
140
141 let feature_metadata = metadata.features
142 .into_iter()
143 .find(|f| f.name == feature)
144 .ok_or(StatusCode::NOT_FOUND)?;
145
146 Ok(Json(ApiResponse::success(feature_metadata.into())))
147}
148
149pub async fn get_operation(
152 Path((provider, feature, operation)): Path<(String, String, String)>,
153 State(state): State<AppState>,
154) -> Result<Json<ApiResponse<OperationInfo>>, StatusCode> {
155 let route = Route::new(provider, feature, operation);
156
157 match state.router.get_route_metadata(&route).await {
158 Ok(metadata) => {
159 let operation_info = OperationInfo {
160 name: metadata.operation_name,
161 description: metadata.operation_description,
162 arguments: metadata.operation_arguments.into_iter().map(Into::into).collect(),
163 return_type: metadata.operation_return_type,
164 is_mutating: metadata.is_mutating,
165 estimated_duration_ms: metadata.estimated_duration_ms,
166 };
167 Ok(Json(ApiResponse::success(operation_info)))
168 }
169 Err(_) => Err(StatusCode::NOT_FOUND),
170 }
171}
172
173pub async fn execute_operation(
176 Path((provider, feature, operation)): Path<(String, String, String)>,
177 Query(query): Query<ExecuteQuery>,
178 State(state): State<AppState>,
179 body: Option<Json<ExecuteRequest>>,
180) -> Result<Json<ApiResponse<ExecutionResult>>, StatusCode> {
181 let start_time = Instant::now();
182
183 let mut args = query.args;
185 if let Some(Json(request)) = body {
186 args.extend(request.args);
187 }
188
189 let route = Route::new(provider.clone(), feature.clone(), operation.clone());
190
191 match state.router.route_request(route, args).await {
192 Ok(result) => {
193 let execution_time = start_time.elapsed().as_millis() as u64;
194
195 let execution_result = ExecutionResult {
196 result,
197 execution_time_ms: execution_time,
198 provider,
199 feature,
200 operation,
201 };
202
203 Ok(Json(ApiResponse::success(execution_result)))
204 }
205 Err(error) => {
206 let api_error = match &error {
207 ProviderError::NotFound(name) => {
208 let msg = format!("Provider '{}' not found", name);
209 ApiError::new("PROVIDER_NOT_FOUND", msg.as_str())
210 }
211 ProviderError::FeatureNotSupported { provider, feature } => {
212 let msg = format!("Feature '{}' not supported by provider '{}'", feature, provider);
213 ApiError::new("FEATURE_NOT_SUPPORTED", msg.as_str())
214 }
215 ProviderError::OperationNotSupported { provider, feature, operation } => {
216 let msg = format!("Operation '{}' not supported by feature '{}' in provider '{}'",
217 operation, feature, provider);
218 ApiError::new("OPERATION_NOT_SUPPORTED", msg.as_str())
219 }
220 ProviderError::InvalidRoute(msg) => {
221 ApiError::new("INVALID_ROUTE", msg.as_str())
222 }
223 ProviderError::ExecutionFailed(msg) => {
224 ApiError::new("EXECUTION_FAILED", msg.as_str())
225 }
226 ProviderError::LoadingFailed(msg) => {
227 ApiError::new("LOADING_FAILED", msg.as_str())
228 }
229 ProviderError::InitializationFailed(msg) => {
230 ApiError::new("INITIALIZATION_FAILED", msg.as_str())
231 }
232 ProviderError::Io(err) => {
233 ApiError::new("IO_ERROR", err.to_string().as_str())
234 }
235 ProviderError::LibraryError(err) => {
236 ApiError::new("LIBRARY_ERROR", err.to_string().as_str())
237 }
238 ProviderError::InvalidArguments(msg) => {
239 ApiError::new("INVALID_ARGUMENTS", msg.as_str())
240 }
241 };
242
243 let _status_code = match error {
244 ProviderError::NotFound(_) => StatusCode::NOT_FOUND,
245 ProviderError::FeatureNotSupported { .. } => StatusCode::NOT_FOUND,
246 ProviderError::OperationNotSupported { .. } => StatusCode::NOT_FOUND,
247 ProviderError::InvalidRoute(_) => StatusCode::BAD_REQUEST,
248 _ => StatusCode::INTERNAL_SERVER_ERROR,
249 };
250
251 let _error_response = ApiResponse::<ExecutionResult>::error(api_error);
253
254 Err(StatusCode::INTERNAL_SERVER_ERROR)
257 }
258 }
259}
260
261pub async fn list_routes(State(state): State<AppState>) -> Json<ApiResponse<Vec<String>>> {
264 match state.router.get_available_routes().await {
265 Ok(routes) => {
266 let route_paths: Vec<String> = routes
267 .into_iter()
268 .map(|route| route.to_url_path())
269 .collect();
270 Json(ApiResponse::success(route_paths))
271 }
272 Err(_) => {
273 let error = ApiError::new("ROUTES_UNAVAILABLE", "Failed to retrieve available routes");
274 Json(ApiResponse::error(error))
275 }
276 }
277}
278
279pub async fn get_stats(State(state): State<AppState>) -> Json<ApiResponse<serde_json::Value>> {
282 let stats = state.registry.get_statistics().await;
283 let stats_json = serde_json::to_value(stats).unwrap_or_default();
285 Json(ApiResponse::success(stats_json))
286}
287
288pub async fn exec_action(
291 State(state): State<AppState>,
292 Json(request): Json<ExecActionRequest>,
293) -> Result<Json<ApiResponse<ExecutionResult>>, StatusCode> {
294 let start_time = Instant::now();
295
296 let event_name = format!("{}.{}", request.feature, request.operation);
298
299 let args_value = serde_json::to_value(request.args).unwrap_or_default();
301
302 match state.event_registry.execute(&event_name, args_value).await {
303 Ok(result) => {
304 let execution_time = start_time.elapsed().as_millis() as u64;
305
306 let execution_result = ExecutionResult {
307 provider: request.provider,
308 feature: request.feature,
309 operation: request.operation,
310 result,
311 execution_time_ms: execution_time,
312 };
313
314 Ok(Json(ApiResponse::success(execution_result)))
315 }
316 Err(e) => {
317 let error = if e.contains("not found") {
318 ApiError::new("EVENT_NOT_FOUND", &e)
319 } else {
320 ApiError::new("EXECUTION_FAILED", &e)
321 };
322
323 Ok(Json(ApiResponse::error(error)))
324 }
325 }
326}
327
328fn get_memory_usage_mb() -> f64 {
330 let _process = std::process::Command::new("tasklist")
333 .args(&["/FI", "PID eq {}", "/FO", "CSV"])
334 .output();
335
336 0.0
338}