Update data

This commit is contained in:
Andras Schmelczer 2026-05-14 08:17:10 +01:00
parent a4103b0896
commit 273d7a83ee
15 changed files with 716 additions and 316 deletions

View file

@ -215,6 +215,14 @@ 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,
@ -246,6 +254,8 @@ 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),
@ -510,7 +520,10 @@ async fn main() -> anyhow::Result<()> {
let public_url_tiles = initial_state.public_url.clone();
let api = Router::new()
.route("/api/features", get(routes::get_features))
.route(
"/api/features",
get(routes::get_features).layer(ConcurrencyLimitLayer::new(20)),
)
.route(
"/api/hexagons",
get(routes::get_hexagons).layer(ConcurrencyLimitLayer::new(20)),
@ -519,30 +532,57 @@ async fn main() -> anyhow::Result<()> {
"/api/postcodes",
get(routes::get_postcodes).layer(ConcurrencyLimitLayer::new(20)),
)
.route("/api/postcode/{postcode}", get(routes::get_postcode_lookup))
.route("/api/nearest-postcode", get(routes::get_nearest_postcode))
.route(
"/api/postcode/{postcode}",
get(routes::get_postcode_lookup).layer(ConcurrencyLimitLayer::new(20)),
)
.route(
"/api/nearest-postcode",
get(routes::get_nearest_postcode).layer(ConcurrencyLimitLayer::new(10)),
)
.route(
"/api/pois",
get(routes::get_pois).layer(ConcurrencyLimitLayer::new(20)),
)
.route("/api/poi-categories", get(routes::get_poi_categories))
.route("/api/places", get(routes::get_places))
.route("/api/travel-modes", get(routes::get_travel_modes))
.route(
"/api/poi-categories",
get(routes::get_poi_categories).layer(ConcurrencyLimitLayer::new(20)),
)
.route(
"/api/places",
get(routes::get_places).layer(ConcurrencyLimitLayer::new(10)),
)
.route(
"/api/travel-modes",
get(routes::get_travel_modes).layer(ConcurrencyLimitLayer::new(20)),
)
.route(
"/api/travel-destinations",
get(routes::get_travel_destinations),
get(routes::get_travel_destinations).layer(ConcurrencyLimitLayer::new(10)),
)
.route(
"/api/journey",
get(routes::get_journey).layer(ConcurrencyLimitLayer::new(10)),
)
.route("/api/journey", get(routes::get_journey))
.route(
"/api/hexagon-properties",
get(routes::get_hexagon_properties),
get(routes::get_hexagon_properties).layer(ConcurrencyLimitLayer::new(10)),
)
.route(
"/api/filter-counts",
get(routes::get_filter_counts).layer(ConcurrencyLimitLayer::new(5)),
)
.route(
"/api/hexagon-stats",
get(routes::get_hexagon_stats).layer(ConcurrencyLimitLayer::new(5)),
)
.route(
"/api/postcode-stats",
get(routes::get_postcode_stats).layer(ConcurrencyLimitLayer::new(5)),
)
.route("/api/filter-counts", get(routes::get_filter_counts))
.route("/api/hexagon-stats", get(routes::get_hexagon_stats))
.route("/api/postcode-stats", get(routes::get_postcode_stats))
.route(
"/api/postcode-properties",
get(routes::get_postcode_properties),
get(routes::get_postcode_properties).layer(ConcurrencyLimitLayer::new(10)),
)
.route(
"/api/screenshot",
@ -552,13 +592,26 @@ async fn main() -> anyhow::Result<()> {
"/api/export",
get(routes::get_export).layer(ConcurrencyLimitLayer::new(3)),
)
.route("/api/me", get(routes::get_me))
.route("/api/shorten", post(routes::post_shorten))
.route(
"/api/me",
get(routes::get_me).layer(ConcurrencyLimitLayer::new(20)),
)
.route(
"/api/shorten",
post(routes::post_shorten).layer(ConcurrencyLimitLayer::new(5)),
)
.route(
"/api/share-links",
get(routes::get_share_links).layer(ConcurrencyLimitLayer::new(10)),
)
.route(
"/api/ai-filters",
post(routes::post_ai_filters).layer(ConcurrencyLimitLayer::new(5)),
)
.route("/api/streetview", get(routes::get_streetview))
.route(
"/api/streetview",
get(routes::get_streetview).layer(ConcurrencyLimitLayer::new(5)),
)
.route(
"/api/rightmove-search",
get(routes::get_rightmove_redirect).layer(ConcurrencyLimitLayer::new(10)),
@ -567,23 +620,44 @@ async fn main() -> anyhow::Result<()> {
"/api/newsletter",
patch(routes::patch_newsletter).layer(ConcurrencyLimitLayer::new(10)),
)
.route("/api/pricing", get(routes::get_pricing))
.route(
"/api/pricing",
get(routes::get_pricing).layer(ConcurrencyLimitLayer::new(20)),
)
.route(
"/api/checkout",
post(routes::post_checkout).layer(ConcurrencyLimitLayer::new(10)),
)
.route("/api/stripe-webhook", post(routes::post_stripe_webhook))
.route(
"/api/stripe-webhook",
post(routes::post_stripe_webhook).layer(ConcurrencyLimitLayer::new(10)),
)
.route(
"/api/invites",
get(routes::get_invites).post(routes::post_invites),
get(routes::get_invites)
.post(routes::post_invites)
.layer(ConcurrencyLimitLayer::new(5)),
)
.route(
"/api/invite/{code}",
get(routes::get_invite).layer(ConcurrencyLimitLayer::new(5)),
)
.route(
"/api/redeem-invite",
post(routes::post_redeem_invite).layer(ConcurrencyLimitLayer::new(5)),
)
.route(
"/s/{code}",
get(routes::get_short_url).layer(ConcurrencyLimitLayer::new(10)),
)
.route("/api/invite/{code}", get(routes::get_invite))
.route("/api/redeem-invite", post(routes::post_redeem_invite))
.route("/s/{code}", get(routes::get_short_url))
.route(
"/api/telemetry",
post(routes::post_telemetry).layer(ConcurrencyLimitLayer::new(20)),
)
.route(
"/pb/api/realtime",
any(routes::proxy_to_pocketbase).layer(ConcurrencyLimitLayer::new(50)),
)
.route(
"/pb/{*rest}",
any(routes::proxy_to_pocketbase).layer(ConcurrencyLimitLayer::new(10)),
@ -591,19 +665,28 @@ async fn main() -> anyhow::Result<()> {
// Tile routes use a different state type — kept as closures
.route(
"/api/tiles/{z}/{x}/{y}",
get(move |path| routes::get_tile(axum::extract::State(reader_tile.clone()), path)),
get(move |path| routes::get_tile(axum::extract::State(reader_tile.clone()), path))
.layer(ConcurrencyLimitLayer::new(30)),
)
.route(
"/api/tiles/style.json",
get(move |query| {
let pu = public_url_tiles.clone();
routes::get_style(axum::extract::State(reader_style.clone()), pu, query)
}),
})
.layer(ConcurrencyLimitLayer::new(20)),
)
.route("/health", get(|| async { "ok" }))
.route(
"/metrics",
get(move || metrics::metrics_handler(metrics_handle.clone())),
get(move |headers| {
metrics::metrics_handler(
metrics_handle.clone(),
metrics_bearer_token.clone(),
allow_public_metrics,
headers,
)
}),
)
.with_state(shared.clone());