This commit is contained in:
Andras Schmelczer 2026-05-16 16:26:36 +01:00
parent e9a06417ad
commit 5e5d9f9a1c
16 changed files with 280 additions and 44 deletions

View file

@ -10,7 +10,8 @@ pub const H3_REQUEST_MAX: u8 = 12;
pub const SERVER_ADDRESS: &str = "0.0.0.0:8001";
pub const GRID_CELL_SIZE: f32 = 0.01;
pub const MAX_POIS_PER_REQUEST: usize = 10000;
pub const MAX_CELLS_PER_REQUEST: usize = 200000;
pub const MAX_POIS_PER_REQUEST: usize = 3000;
pub const DEFAULT_PROPERTIES_LIMIT: usize = 100;
pub const MAX_PRICE_HISTORY_POINTS: usize = 5000;

View file

@ -216,14 +216,6 @@ struct Cli {
#[arg(long, env = "STRIPE_REFERRAL_COUPON_ID")]
stripe_referral_coupon_id: String,
/// Bearer token required to scrape /metrics.
#[arg(long, env = "METRICS_BEARER_TOKEN")]
metrics_bearer_token: Option<String>,
/// Allow unauthenticated /metrics scraping when no METRICS_BEARER_TOKEN is set.
#[arg(long, env = "ALLOW_PUBLIC_METRICS", default_value_t = false)]
allow_public_metrics: bool,
/// Google OAuth client ID for PocketBase SSO
#[arg(long, env = "GOOGLE_OAUTH_CLIENT_ID")]
google_oauth_client_id: String,
@ -255,8 +247,6 @@ async fn main() -> anyhow::Result<()> {
info!("Prometheus metrics initialized");
let cli = Cli::parse();
let metrics_bearer_token = cli.metrics_bearer_token.clone();
let allow_public_metrics = cli.allow_public_metrics;
for (label, path) in [
("Properties", &cli.properties),
@ -680,13 +670,8 @@ async fn main() -> anyhow::Result<()> {
.route("/health", get(|| async { "ok" }))
.route(
"/metrics",
get(move |headers| {
metrics::metrics_handler(
metrics_handle.clone(),
metrics_bearer_token.clone(),
allow_public_metrics,
headers,
)
get(move |connect_info| {
metrics::metrics_handler(metrics_handle.clone(), connect_info)
}),
)
.with_state(shared.clone());
@ -732,6 +717,11 @@ async fn main() -> anyhow::Result<()> {
.await
.with_context(|| format!("Failed to bind to {addr}"))?;
info!("Server listening on {}", addr);
axum::serve(listener, app).await.context("Server error")?;
axum::serve(
listener,
app.into_make_service_with_connect_info::<std::net::SocketAddr>(),
)
.await
.context("Server error")?;
Ok(())
}

View file

@ -1,10 +1,11 @@
use axum::body::Body;
use axum::extract::Request;
use axum::extract::{ConnectInfo, Request};
use axum::http::StatusCode;
use axum::middleware::Next;
use axum::response::{IntoResponse, Response};
use metrics::{counter, gauge, histogram};
use metrics_exporter_prometheus::{Matcher, PrometheusBuilder, PrometheusHandle};
use std::net::{IpAddr, SocketAddr};
use std::time::Instant;
/// Initialize the Prometheus metrics exporter and return a handle for rendering metrics.
@ -144,17 +145,39 @@ fn normalize_path(path: &str) -> String {
"/other".to_string()
}
/// Handler for the /metrics endpoint.
pub async fn metrics_handler(handle: PrometheusHandle) -> impl IntoResponse {
// Update process metrics before rendering
/// Handler for the /metrics endpoint. Only accepts requests from peers on the
/// same private network (loopback, RFC1918, or IPv6 unique/link-local).
pub async fn metrics_handler(
handle: PrometheusHandle,
ConnectInfo(peer): ConnectInfo<SocketAddr>,
) -> Response {
if !is_same_network(peer.ip()) {
return StatusCode::FORBIDDEN.into_response();
}
update_process_metrics();
match handle.render() {
output if !output.is_empty() => (StatusCode::OK, output),
output if !output.is_empty() => (StatusCode::OK, output).into_response(),
_ => (
StatusCode::INTERNAL_SERVER_ERROR,
"Failed to render metrics".to_string(),
),
)
.into_response(),
}
}
fn is_same_network(ip: IpAddr) -> bool {
match ip {
IpAddr::V4(v4) => v4.is_loopback() || v4.is_private() || v4.is_link_local(),
IpAddr::V6(v6) => {
v6.is_loopback()
|| (v6.segments()[0] & 0xfe00) == 0xfc00
|| (v6.segments()[0] & 0xffc0) == 0xfe80
|| v6.to_ipv4_mapped().is_some_and(|v4| {
v4.is_loopback() || v4.is_private() || v4.is_link_local()
})
}
}
}