Skip to content

Commit 565b745

Browse files
Copilot0xrinegade
andcommitted
Add OpenAI API rate limiting and improve error handling throughout main.rs
Co-authored-by: 0xrinegade <[email protected]>
1 parent c36c6eb commit 565b745

File tree

2 files changed

+68
-15
lines changed

2 files changed

+68
-15
lines changed

src/main.rs

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -403,8 +403,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
403403
}
404404
}
405405
Err(e) => {
406-
eprintln!("Error getting node status: {}", e);
407-
exit(1);
406+
return Err(format!("Error getting node status: {}", e).into());
408407
}
409408
}
410409
}
@@ -425,8 +424,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
425424
}
426425
}
427426
Err(e) => {
428-
eprintln!("Error getting node info: {}", e);
429-
exit(1);
427+
return Err(format!("Error getting node info: {}", e).into());
430428
}
431429
}
432430
}
@@ -439,8 +437,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
439437
match nodes::restart_node(node_id) {
440438
Ok(_) => println!("Node {} restarted successfully", node_id),
441439
Err(e) => {
442-
eprintln!("Error restarting node: {}", e);
443-
exit(1);
440+
return Err(format!("Error restarting node: {}", e).into());
444441
}
445442
}
446443
}
@@ -453,8 +450,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
453450
match nodes::stop_node(node_id) {
454451
Ok(_) => println!("Node {} stopped successfully", node_id),
455452
Err(e) => {
456-
eprintln!("Error stopping node: {}", e);
457-
exit(1);
453+
return Err(format!("Error stopping node: {}", e).into());
458454
}
459455
}
460456
}
@@ -478,8 +474,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
478474
}
479475
}
480476
Err(e) => {
481-
eprintln!("Error getting node logs: {}", e);
482-
exit(1);
477+
return Err(format!("Error getting node logs: {}", e).into());
483478
}
484479
}
485480
}

src/utils/audit.rs

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,17 @@ use serde::{Deserialize, Serialize};
99
use std::collections::HashMap;
1010
use std::path::Path;
1111
use std::process::Command;
12+
use std::time::Duration;
13+
use tokio::time::sleep;
1214

1315
use crate::utils::diagnostics::{DiagnosticCoordinator, DiagnosticResults, IssueSeverity, IssueCategory};
1416

15-
/// OpenAI API client for AI-powered analysis
17+
/// OpenAI API client for AI-powered analysis with rate limiting and retry logic
1618
pub struct OpenAIClient {
1719
api_key: String,
1820
client: reqwest::Client,
21+
max_retries: u32,
22+
base_delay: Duration,
1923
}
2024

2125
/// AI analysis result from OpenAI
@@ -36,16 +40,46 @@ pub struct AIEnhancedFinding {
3640
}
3741

3842
impl OpenAIClient {
39-
/// Create a new OpenAI client
43+
/// Create a new OpenAI client with retry and rate limiting
4044
pub fn new(api_key: String) -> Self {
4145
Self {
4246
api_key,
43-
client: reqwest::Client::new(),
47+
client: reqwest::Client::builder()
48+
.timeout(Duration::from_secs(30))
49+
.build()
50+
.unwrap_or_else(|_| reqwest::Client::new()),
51+
max_retries: 3,
52+
base_delay: Duration::from_millis(1000),
4453
}
4554
}
4655

47-
/// Analyze a security finding using OpenAI
56+
/// Analyze a security finding using OpenAI with retry logic
4857
pub async fn analyze_finding(&self, finding: &AuditFinding) -> Result<AIAnalysis> {
58+
for attempt in 0..=self.max_retries {
59+
match self.try_analyze_finding(finding).await {
60+
Ok(analysis) => return Ok(analysis),
61+
Err(e) if attempt < self.max_retries => {
62+
// Check if it's a rate limit error
63+
if e.to_string().contains("rate limit") || e.to_string().contains("429") {
64+
let delay = self.base_delay * 2_u32.pow(attempt);
65+
eprintln!("⏳ Rate limited, retrying in {}ms... (attempt {}/{})",
66+
delay.as_millis(), attempt + 1, self.max_retries);
67+
sleep(delay).await;
68+
} else {
69+
eprintln!("⚠️ OpenAI API error, retrying... (attempt {}/{}): {}",
70+
attempt + 1, self.max_retries, e);
71+
sleep(self.base_delay).await;
72+
}
73+
},
74+
Err(e) => return Err(e),
75+
}
76+
}
77+
78+
Err(anyhow::anyhow!("OpenAI analysis failed after {} retries", self.max_retries))
79+
}
80+
81+
/// Single attempt to analyze a finding
82+
async fn try_analyze_finding(&self, finding: &AuditFinding) -> Result<AIAnalysis> {
4983
let prompt = format!(
5084
"Analyze this security finding and provide enhanced insights:\n\n\
5185
Title: {}\n\
@@ -123,8 +157,32 @@ impl OpenAIClient {
123157
Ok(ai_analysis)
124158
}
125159

126-
/// Analyze code content for security issues
160+
/// Analyze code content for security issues with retry logic
127161
pub async fn analyze_code(&self, code_content: &str, file_path: &str) -> Result<Vec<AuditFinding>> {
162+
for attempt in 0..=self.max_retries {
163+
match self.try_analyze_code(code_content, file_path).await {
164+
Ok(findings) => return Ok(findings),
165+
Err(e) if attempt < self.max_retries => {
166+
if e.to_string().contains("rate limit") || e.to_string().contains("429") {
167+
let delay = self.base_delay * 2_u32.pow(attempt);
168+
eprintln!("⏳ Rate limited during code analysis, retrying in {}ms... (attempt {}/{})",
169+
delay.as_millis(), attempt + 1, self.max_retries);
170+
sleep(delay).await;
171+
} else {
172+
eprintln!("⚠️ OpenAI code analysis error, retrying... (attempt {}/{}): {}",
173+
attempt + 1, self.max_retries, e);
174+
sleep(self.base_delay).await;
175+
}
176+
},
177+
Err(e) => return Err(e),
178+
}
179+
}
180+
181+
Err(anyhow::anyhow!("OpenAI code analysis failed after {} retries", self.max_retries))
182+
}
183+
184+
/// Single attempt to analyze code
185+
async fn try_analyze_code(&self, code_content: &str, file_path: &str) -> Result<Vec<AuditFinding>> {
128186
let prompt = format!(
129187
"Analyze this Rust code file for security vulnerabilities:\n\n\
130188
File: {}\n\

0 commit comments

Comments
 (0)