mod forwarder;
mod monitor;
mod storage;
use axum::{
extract::State,
routing::{get, post, delete},
Router, Json,
};
use std::net::SocketAddr;
use tracing_subscriber;
use std::sync::Arc;
use forwarder::{ForwardManager, ForwardRule};
use storage::FileStorage;
type SharedState = Arc<AppState>;
struct AppState {
forward_manager: ForwardManager,
}
#[tokio::main]
async fn main() {
tracing_subscriber::fmt::init();
let storage = FileStorage::new("data/rules.json")
.expect("Failed to initialize storage");
let forward_manager = ForwardManager::new(storage);
forward_manager.restore_rules()
.await
.expect("Failed to restore rules");
let state = Arc::new(AppState {
forward_manager,
});
let app = Router::new()
.route("/api/stats", get(get_stats))
.route("/api/forward", post(create_forward))
.route("/api/forward/:id", delete(delete_forward))
.route("/api/forward", get(list_forwards))
.with_state(state);
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
println!("Listening on {}", addr);
axum::Server::bind(&addr)
.serve(app.into_make_service())
.await
.unwrap();
}
async fn get_stats() -> axum::Json<monitor::SystemStats> {
let monitor = monitor::Monitor::new();
let stats = monitor.collect_stats().await.unwrap();
axum::Json(stats)
}
async fn create_forward(
State(state): State<SharedState>,
Json(rule): Json<ForwardRule>,
) -> Result<Json<ForwardRule>, String> {
state
.forward_manager
.add_rule(rule.clone())
.await
.map_err(|e| e.to_string())?;
Ok(Json(rule))
}
async fn delete_forward(
State(state): State<SharedState>,
axum::extract::Path(id): axum::extract::Path<String>,
) -> Result<(), String> {
state
.forward_manager
.remove_rule(&id)
.await
.map_err(|e| e.to_string())
}
async fn list_forwards(
State(state): State<SharedState>,
) -> Json<Vec<ForwardRule>> {
Json(state.forward_manager.get_rules().await)
}