use std::io::{self, Read, Write};
use std::net::{TcpListener, TcpStream};
use std::sync::{Arc, Mutex};
use std::collections::HashMap;
use tokio::sync::mpsc;
use tokio::time;
async fn make_api_request(api_url: &str) -> Result<String, reqwest::Error> {
let response = reqwest::get(api_url).await?;
Ok(response.text().await?)
}
async fn handle_request(mut stream: TcpStream, data: Arc<Mutex<HashMap<u64, String>>>, tx: mpsc::Sender<String>) {
let mut buffer = Vec::new();
if stream.read_to_end(&mut buffer).is_err() {
return;
}
let request_str = String::from_utf8_lossy(&buffer);
let request_lines: Vec<&str> = request_str.lines().collect();
let path = if let Some(first_line) = request_lines.first() {
let parts: Vec<&str> = first_line.split_whitespace().collect();
if parts.len() >= 2 {
parts[1]
} else {
return;
}
} else {
return;
};
time::sleep(tokio::time::Duration::from_secs(1)).await;
let api_url = format!("https://api.example.com{}", path);
match make_api_request(&api_url).await {
Ok(api_response) => {
let response = format!("HTTP/1.1 200 OK\r\n\r\n{}", api_response);
if stream.write_all(response.as_bytes()).is_err() {
return;
}
let stream_id = stream.peer_addr().unwrap().port();
data.lock().unwrap().insert(stream_id as u64, api_response.clone());
if let Err(err) = tx.send(api_response.clone()).await {
eprintln!("Error sending response to channel: {}", err);
}
}
Err(err) => {
let response = format!("HTTP/1.1 500 Internal Server Error\r\n\r\n{}", err);
if stream.write_all(response.as_bytes()).is_err() {
return;
}
}
}
if stream.flush().is_err() {
return;
}
}
pub(crate) async fn start_server(addr: &str, api_url: String, tx: mpsc::Sender<String>) -> io::Result<()> {
let listener = TcpListener::bind(addr)?;
println!("Server running on http://{}", addr);
let data = Arc::new(Mutex::new(HashMap::new()));
tokio::spawn(async move {
for stream in listener.incoming() {
match stream {
Ok(stream) => {
let data = Arc::clone(&data);
let tx_clone = tx.clone();
tokio::spawn(handle_request(stream, data, tx_clone));
}
Err(e) => {
eprintln!("Error accepting connection: {}", e);
}
}
}
});
loop {
time::sleep(tokio::time::Duration::from_secs(1)).await;
}
}