sub-aligator/src/handlers/partials.rs

78 lines
2.4 KiB
Rust

use crate::allocator::{find_next_subnet, usable_host_count};
use crate::models::Pool;
use crate::state::AppState;
use crate::templates::PoolPreviewTemplate;
use askama::Template;
use axum::extract::{Path, Query, State};
use axum::response::{Html, IntoResponse};
use serde::Deserialize;
use tracing::error;
#[derive(Deserialize, Debug)]
pub struct PreviewQuery {
pub prefix_length: i32,
}
pub async fn pool_preview(
State(state): State<AppState>,
Path(slug): Path<String>,
Query(q): Query<PreviewQuery>,
) -> impl IntoResponse {
let pool: Option<Pool> = sqlx::query_as("SELECT * FROM pools WHERE slug = ? AND enabled = true")
.bind(&slug)
.fetch_optional(&state.pool)
.await
.unwrap_or_default();
let pool = match pool {
Some(p) => p,
None => {
let template = PoolPreviewTemplate {
cidr: String::new(),
prefix_length: q.prefix_length,
address_count: 0,
usable_host_count: 0,
has_error: true,
error: "Pool does not exist.".to_string(),
};
return Html(template.render().unwrap_or_default());
}
};
let active: Vec<String> = sqlx::query_scalar(
"SELECT cidr FROM allocations WHERE pool_id = ? AND status IN ('active', 'reserved')",
)
.bind(pool.id)
.fetch_all(&state.pool)
.await
.unwrap_or_default();
let allowed = pool.allowed_prefixes();
let template = match find_next_subnet(&pool.cidr, q.prefix_length, &allowed, &active) {
Ok(info) => PoolPreviewTemplate {
cidr: info.cidr,
prefix_length: info.prefix_length,
address_count: info.address_count,
usable_host_count: info.usable_host_count,
has_error: false,
error: String::new(),
},
Err(e) => PoolPreviewTemplate {
cidr: String::new(),
prefix_length: q.prefix_length,
address_count: usable_host_count(q.prefix_length),
usable_host_count: usable_host_count(q.prefix_length),
has_error: true,
error: e.to_string(),
},
};
match template.render() {
Ok(html) => Html(html),
Err(e) => {
error!("Preview template render error: {}", e);
Html("Preview error.".to_string())
}
}
}