1use axum::{
4 extract::{State, Json},
5 http::StatusCode,
6 response::Json as JsonResponse,
7};
8use std::sync::Arc;
9use tokio::sync::RwLock;
10use std::time::Instant;
11
12use crate::models::*;
13use fukurow_engine::ReasonerEngine;
14use fukurow_domain_cyber::threat_intelligence::ThreatProcessor;
15
16#[derive(Clone)]
18pub struct AppState {
19 pub reasoner: Arc<ReasonerEngine>,
20 pub threat_processor: Arc<RwLock<ThreatProcessor>>,
21 pub start_time: Instant,
22}
23
24pub async fn health_check(State(state): State<AppState>) -> JsonResponse<ApiResponse<HealthResponse>> {
26 let uptime = state.start_time.elapsed();
27
28 let response = HealthResponse {
29 status: "healthy".to_string(),
30 version: env!("CARGO_PKG_VERSION").to_string(),
31 uptime_seconds: uptime.as_secs(),
32 };
33
34 JsonResponse(ApiResponse::success(response))
35}
36
37pub async fn submit_event(
39 State(state): State<AppState>,
40 Json(request): Json<SubmitEventRequest>,
41) -> Result<JsonResponse<ApiResponse<String>>, (StatusCode, JsonResponse<ApiResponse<String>>)> {
42 match state.reasoner.add_event(request.event).await {
43 Ok(_) => {
44 let response = ApiResponse::success("Event submitted successfully".to_string());
45 Ok(JsonResponse(response))
46 }
47 Err(e) => {
48 let error_response = ApiResponse::error(format!("Failed to submit event: {}", e));
49 Err((StatusCode::INTERNAL_SERVER_ERROR, JsonResponse(error_response)))
50 }
51 }
52}
53
54pub async fn execute_reasoning(
56 State(state): State<AppState>,
57 Json(_request): Json<ReasoningRequest>,
58) -> Result<JsonResponse<ApiResponse<ReasoningResponse>>, (StatusCode, JsonResponse<ApiResponse<String>>)> {
59 let start = Instant::now();
60
61 match state.reasoner.reason().await {
62 Ok(actions) => {
63 let execution_time = start.elapsed();
64
65 let response = ReasoningResponse {
66 actions,
67 execution_time_ms: execution_time.as_millis() as u64,
68 event_count: 0, };
70
71 Ok(JsonResponse(ApiResponse::success(response)))
72 }
73 Err(e) => {
74 let error_response = ApiResponse::error(format!("Reasoning failed: {}", e));
75 Err((StatusCode::INTERNAL_SERVER_ERROR, JsonResponse(error_response)))
76 }
77 }
78}
79
80pub async fn query_graph(
82 State(state): State<AppState>,
83 Json(request): Json<GraphQueryRequest>,
84) -> Result<JsonResponse<ApiResponse<GraphQueryResponse>>, (StatusCode, JsonResponse<ApiResponse<String>>)> {
85 let store = state.reasoner.get_graph_store().await;
86 let graph_store = store.read().await;
87
88 let triples = graph_store.find_triples(
89 request.subject.as_deref(),
90 request.predicate.as_deref(),
91 request.object.as_deref(),
92 );
93
94 let count = triples.len();
95 let response = GraphQueryResponse {
96 triples: triples.into_iter().map(|stored| stored.triple.clone()).collect(),
97 count,
98 };
99
100 Ok(JsonResponse(ApiResponse::success(response)))
101}
102
103pub async fn get_stats(State(state): State<AppState>) -> JsonResponse<ApiResponse<StatsResponse>> {
105 let uptime = state.start_time.elapsed();
106
107 let response = StatsResponse {
109 total_events: 0,
110 total_actions: 0,
111 uptime_seconds: uptime.as_secs(),
112 memory_usage_mb: None, };
114
115 JsonResponse(ApiResponse::success(response))
116}
117
118pub async fn reset_reasoner(
120 State(_state): State<AppState>,
121) -> Result<JsonResponse<ApiResponse<String>>, (StatusCode, JsonResponse<ApiResponse<String>>)> {
122 let error_response = ApiResponse::error("Reset functionality not yet implemented".to_string());
124 Err((StatusCode::NOT_IMPLEMENTED, JsonResponse(error_response)))
125}
126
127pub async fn add_rule(
129 State(_state): State<AppState>,
130 Json(_request): Json<AddRuleRequest>,
131) -> Result<JsonResponse<ApiResponse<String>>, (StatusCode, JsonResponse<ApiResponse<String>>)> {
132 let error_response = ApiResponse::error("Adding custom rules not yet implemented".to_string());
135 Err((StatusCode::NOT_IMPLEMENTED, JsonResponse(error_response)))
136}
137
138pub async fn get_threat_intel(
140 State(state): State<AppState>,
141) -> JsonResponse<ApiResponse<ThreatIntelResponse>> {
142 let threat_processor = state.threat_processor.read().await;
143 let statistics = threat_processor.get_statistics();
144
145 let response = ThreatIntelResponse {
146 indicators_count: statistics.get("total_indicators").copied().unwrap_or(0),
147 sources_count: statistics.get("sources").copied().unwrap_or(0),
148 last_updated: chrono::Utc::now().timestamp(),
149 statistics,
150 };
151
152 JsonResponse(ApiResponse::success(response))
153}
154
155pub async fn export_threat_indicators(
157 State(state): State<AppState>,
158) -> Result<JsonResponse<ApiResponse<String>>, (StatusCode, JsonResponse<ApiResponse<String>>)> {
159 let threat_processor = state.threat_processor.read().await;
160
161 match threat_processor.export_indicators() {
162 Ok(json_data) => {
163 Ok(JsonResponse(ApiResponse::success(json_data)))
164 }
165 Err(e) => {
166 let error_response = ApiResponse::error(format!("Failed to export indicators: {}", e));
167 Err((StatusCode::INTERNAL_SERVER_ERROR, JsonResponse(error_response)))
168 }
169 }
170}
171
172pub async fn import_threat_indicators(
174 State(state): State<AppState>,
175 Json(json_data): Json<String>,
176) -> Result<JsonResponse<ApiResponse<String>>, (StatusCode, JsonResponse<ApiResponse<String>>)> {
177 let mut threat_processor = state.threat_processor.write().await;
178
179 match threat_processor.import_indicators(&json_data) {
180 Ok(_) => {
181 let response = ApiResponse::success("Threat indicators imported successfully".to_string());
182 Ok(JsonResponse(response))
183 }
184 Err(e) => {
185 let error_response = ApiResponse::error(format!("Failed to import indicators: {}", e));
186 Err((StatusCode::INTERNAL_SERVER_ERROR, JsonResponse(error_response)))
187 }
188 }
189}