Update data
This commit is contained in:
parent
a4103b0896
commit
273d7a83ee
15 changed files with 716 additions and 316 deletions
|
|
@ -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());
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use serde::Deserialize;
|
|||
use tracing::{info, warn};
|
||||
|
||||
use crate::auth::OptionalUser;
|
||||
use crate::consts::{DEFAULT_PROPERTIES_LIMIT, MAX_PROPERTIES_LIMIT, POSTCODE_SEARCH_OFFSET};
|
||||
use crate::consts::{DEFAULT_PROPERTIES_LIMIT, POSTCODE_SEARCH_OFFSET};
|
||||
use crate::licensing::{check_license_point, resolve_share_code};
|
||||
use crate::parsing::{parse_filters_with_poi, row_passes_filters, row_passes_poi_filters};
|
||||
use crate::state::SharedState;
|
||||
|
|
@ -151,10 +151,7 @@ pub async fn get_postcode_properties(
|
|||
});
|
||||
|
||||
let total = matching_rows.len();
|
||||
let limit = params
|
||||
.limit
|
||||
.unwrap_or(DEFAULT_PROPERTIES_LIMIT)
|
||||
.min(MAX_PROPERTIES_LIMIT);
|
||||
let limit = params.limit.unwrap_or(DEFAULT_PROPERTIES_LIMIT);
|
||||
let page_offset = params.offset.unwrap_or(0);
|
||||
let truncated = total > page_offset + limit;
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ use tracing::info;
|
|||
|
||||
use crate::aggregation::{Aggregator, EnumDistConfig, PoiAggregator};
|
||||
use crate::auth::OptionalUser;
|
||||
use crate::consts::MAX_CELLS_PER_REQUEST;
|
||||
use crate::data::travel_time::TravelData;
|
||||
use crate::licensing::{check_license_bounds, resolve_share_code};
|
||||
use crate::parsing::{
|
||||
|
|
@ -354,73 +353,61 @@ pub async fn get_postcodes(
|
|||
|
||||
features.push(feature);
|
||||
included_postcodes.insert(pc_idx);
|
||||
|
||||
if features.len() >= MAX_CELLS_PER_REQUEST {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if features.len() < MAX_CELLS_PER_REQUEST {
|
||||
for pc_idx in selectable_postcodes {
|
||||
if included_postcodes.contains(&pc_idx) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let (pc_south, pc_west, pc_north, pc_east) = postcode_data.aabbs[pc_idx];
|
||||
|
||||
if !bounds_intersect(
|
||||
pc_south as f64,
|
||||
pc_west as f64,
|
||||
pc_north as f64,
|
||||
pc_east as f64,
|
||||
south,
|
||||
west,
|
||||
north,
|
||||
east,
|
||||
) {
|
||||
filtered_out += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
let geometry = postcode_data.geometry_geojson(pc_idx);
|
||||
let centroid = postcode_data.centroids[pc_idx];
|
||||
let mut props = Map::new();
|
||||
props.insert(
|
||||
"postcode".into(),
|
||||
Value::String(postcode_data.postcodes[pc_idx].clone()),
|
||||
);
|
||||
props.insert("count".into(), Value::from(0));
|
||||
props.insert(
|
||||
"centroid".into(),
|
||||
Value::Array(vec![
|
||||
Value::from(centroid.1 as f64),
|
||||
Value::from(centroid.0 as f64),
|
||||
]),
|
||||
);
|
||||
|
||||
let mut feature = Map::new();
|
||||
feature.insert("type".into(), Value::String("Feature".into()));
|
||||
feature.insert("geometry".into(), geometry);
|
||||
feature.insert("properties".into(), Value::Object(props));
|
||||
|
||||
features.push(feature);
|
||||
|
||||
if features.len() >= MAX_CELLS_PER_REQUEST {
|
||||
break;
|
||||
}
|
||||
for pc_idx in selectable_postcodes {
|
||||
if included_postcodes.contains(&pc_idx) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let (pc_south, pc_west, pc_north, pc_east) = postcode_data.aabbs[pc_idx];
|
||||
|
||||
if !bounds_intersect(
|
||||
pc_south as f64,
|
||||
pc_west as f64,
|
||||
pc_north as f64,
|
||||
pc_east as f64,
|
||||
south,
|
||||
west,
|
||||
north,
|
||||
east,
|
||||
) {
|
||||
filtered_out += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
let geometry = postcode_data.geometry_geojson(pc_idx);
|
||||
let centroid = postcode_data.centroids[pc_idx];
|
||||
let mut props = Map::new();
|
||||
props.insert(
|
||||
"postcode".into(),
|
||||
Value::String(postcode_data.postcodes[pc_idx].clone()),
|
||||
);
|
||||
props.insert("count".into(), Value::from(0));
|
||||
props.insert(
|
||||
"centroid".into(),
|
||||
Value::Array(vec![
|
||||
Value::from(centroid.1 as f64),
|
||||
Value::from(centroid.0 as f64),
|
||||
]),
|
||||
);
|
||||
|
||||
let mut feature = Map::new();
|
||||
feature.insert("type".into(), Value::String("Feature".into()));
|
||||
feature.insert("geometry".into(), geometry);
|
||||
feature.insert("properties".into(), Value::Object(props));
|
||||
|
||||
features.push(feature);
|
||||
}
|
||||
|
||||
histogram!("postcodes_response_count").record(features.len() as f64);
|
||||
|
||||
let truncated = features.len() >= MAX_CELLS_PER_REQUEST;
|
||||
let t_total = t0.elapsed();
|
||||
info!(
|
||||
postcodes_before_filter,
|
||||
matching_postcodes,
|
||||
postcodes_after_filter = features.len(),
|
||||
filtered_out,
|
||||
truncated,
|
||||
bounds = format_args!("{:.6},{:.6},{:.6},{:.6}", south, west, north, east),
|
||||
filters = num_filters,
|
||||
filters_raw = filters_str.as_deref().unwrap_or("-"),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue