Morning improvements
This commit is contained in:
parent
3e9fba5303
commit
53fff3efaa
41 changed files with 2438 additions and 637 deletions
|
|
@ -35,7 +35,7 @@ use tracing_subscriber::layer::SubscriberExt;
|
|||
use tracing_subscriber::util::SubscriberInitExt;
|
||||
use tracing_subscriber::EnvFilter;
|
||||
|
||||
use state::AppState;
|
||||
use state::{AppState, SharedState};
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(
|
||||
|
|
@ -366,19 +366,19 @@ async fn main() -> anyhow::Result<()> {
|
|||
|
||||
let token_cache = Arc::new(auth::TokenCache::new());
|
||||
|
||||
let state = Arc::new(AppState {
|
||||
let app_state = AppState {
|
||||
data: property_data,
|
||||
grid,
|
||||
h3_cells,
|
||||
poi_data,
|
||||
poi_grid,
|
||||
place_data,
|
||||
postcode_data,
|
||||
poi_data: Arc::new(poi_data),
|
||||
poi_grid: Arc::new(poi_grid),
|
||||
place_data: Arc::new(place_data),
|
||||
postcode_data: Arc::new(postcode_data),
|
||||
feature_name_to_index,
|
||||
min_keys,
|
||||
max_keys,
|
||||
avg_keys,
|
||||
poi_category_groups,
|
||||
poi_category_groups: Arc::new(poi_category_groups),
|
||||
features_response,
|
||||
screenshot_url: cli.screenshot_url,
|
||||
public_url: cli.public_url,
|
||||
|
|
@ -397,14 +397,23 @@ async fn main() -> anyhow::Result<()> {
|
|||
stripe_secret_key: cli.stripe_secret_key,
|
||||
stripe_webhook_secret: cli.stripe_webhook_secret,
|
||||
stripe_referral_coupon_id: cli.stripe_referral_coupon_id,
|
||||
});
|
||||
};
|
||||
|
||||
let shared = Arc::new(SharedState::new(
|
||||
app_state,
|
||||
cli.properties,
|
||||
cli.postcode_features,
|
||||
cli.listings_buy,
|
||||
cli.listings_rent,
|
||||
));
|
||||
|
||||
// Start background PocketBase metrics poller (users, saved searches/properties counts)
|
||||
pocketbase::start_metrics_poller(state.clone());
|
||||
pocketbase::start_metrics_poller(shared.clone());
|
||||
|
||||
let initial_state = shared.load_state();
|
||||
let cors = CorsLayer::new()
|
||||
.allow_origin(
|
||||
state
|
||||
initial_state
|
||||
.public_url
|
||||
.parse::<axum::http::HeaderValue>()
|
||||
.expect("public_url must be a valid header value"),
|
||||
|
|
@ -413,183 +422,156 @@ async fn main() -> anyhow::Result<()> {
|
|||
.allow_headers(AllowHeaders::mirror_request())
|
||||
.allow_credentials(true);
|
||||
|
||||
let state_features = state.clone();
|
||||
let state_hexagons = state.clone();
|
||||
let state_postcodes = state.clone();
|
||||
let state_postcode_lookup = state.clone();
|
||||
let state_pois = state.clone();
|
||||
let state_poi_categories = state.clone();
|
||||
let state_hexagon_properties = state.clone();
|
||||
let state_hexagon_stats = state.clone();
|
||||
let state_screenshot = state.clone();
|
||||
let state_export = state.clone();
|
||||
let state_crawler = state.clone();
|
||||
let state_pb = state.clone();
|
||||
let state_postcode_stats = state.clone();
|
||||
let state_postcode_properties = state.clone();
|
||||
let state_places = state.clone();
|
||||
let state_shorten = state.clone();
|
||||
let state_short_url = state.clone();
|
||||
let state_ai_filters = state.clone();
|
||||
let state_streetview = state.clone();
|
||||
let state_newsletter = state.clone();
|
||||
let state_travel_modes = state.clone();
|
||||
let state_travel_destinations = state.clone();
|
||||
let state_checkout = state.clone();
|
||||
let state_stripe_webhook = state.clone();
|
||||
let state_pricing = state.clone();
|
||||
let state_invites_list = state.clone();
|
||||
let state_invites_create = state.clone();
|
||||
let state_invite_get = state.clone();
|
||||
let state_redeem_invite = state.clone();
|
||||
let state_journey = state.clone();
|
||||
let state_telemetry = state.clone();
|
||||
// Each route closure captures a clone of `shared` and calls `load_state()`
|
||||
// at request time to get the latest `Arc<AppState>`. This enables hot-reload:
|
||||
// the reload endpoint swaps in a new AppState, and subsequent requests pick it up.
|
||||
macro_rules! s {
|
||||
() => {
|
||||
shared.clone()
|
||||
};
|
||||
}
|
||||
|
||||
let (s1, s2, s3, s4, s5, s6) = (s!(), s!(), s!(), s!(), s!(), s!());
|
||||
let (s7, s8, s9, s10, s11, s12) = (s!(), s!(), s!(), s!(), s!(), s!());
|
||||
let (s13, s14, s15, s16, s17, s18) = (s!(), s!(), s!(), s!(), s!(), s!());
|
||||
let (s19, s20, s21, s22, s23, s24) = (s!(), s!(), s!(), s!(), s!(), s!());
|
||||
let (s25, s26, s27, s28, s29) = (s!(), s!(), s!(), s!(), s!());
|
||||
let s_crawler = shared.clone();
|
||||
let s_pb = shared.clone();
|
||||
let s_reload = shared.clone();
|
||||
|
||||
let api = Router::new()
|
||||
.route(
|
||||
"/api/features",
|
||||
get(move || routes::get_features(state_features.clone())),
|
||||
get(move || routes::get_features(s1.load_state())),
|
||||
)
|
||||
.route(
|
||||
"/api/hexagons",
|
||||
get(move |ext, query| routes::get_hexagons(state_hexagons.clone(), ext, query)),
|
||||
get(move |ext, query| routes::get_hexagons(s2.load_state(), ext, query)),
|
||||
)
|
||||
.route(
|
||||
"/api/postcodes",
|
||||
get(move |ext, query| routes::get_postcodes(state_postcodes.clone(), ext, query)),
|
||||
get(move |ext, query| routes::get_postcodes(s3.load_state(), ext, query)),
|
||||
)
|
||||
.route(
|
||||
"/api/postcode/{postcode}",
|
||||
get(move |path| routes::get_postcode_lookup(state_postcode_lookup.clone(), path)),
|
||||
get(move |path| routes::get_postcode_lookup(s4.load_state(), path)),
|
||||
)
|
||||
.route(
|
||||
"/api/pois",
|
||||
get(move |query| routes::get_pois(state_pois.clone(), query)),
|
||||
get(move |query| routes::get_pois(s5.load_state(), query)),
|
||||
)
|
||||
.route(
|
||||
"/api/poi-categories",
|
||||
get(move || routes::get_poi_categories(state_poi_categories.clone())),
|
||||
get(move || routes::get_poi_categories(s6.load_state())),
|
||||
)
|
||||
.route(
|
||||
"/api/places",
|
||||
get(move |query| routes::get_places(state_places.clone(), query)),
|
||||
get(move |query| routes::get_places(s7.load_state(), query)),
|
||||
)
|
||||
.route(
|
||||
"/api/travel-modes",
|
||||
get(move || routes::get_travel_modes(state_travel_modes.clone())),
|
||||
get(move || routes::get_travel_modes(s8.load_state())),
|
||||
)
|
||||
.route(
|
||||
"/api/travel-destinations",
|
||||
get(move |query| {
|
||||
routes::get_travel_destinations(state_travel_destinations.clone(), query)
|
||||
}),
|
||||
get(move |query| routes::get_travel_destinations(s9.load_state(), query)),
|
||||
)
|
||||
.route(
|
||||
"/api/journey",
|
||||
get(move |query| routes::get_journey(state_journey.clone(), query)),
|
||||
get(move |query| routes::get_journey(s10.load_state(), query)),
|
||||
)
|
||||
.route(
|
||||
"/api/hexagon-properties",
|
||||
get(move |ext, query| {
|
||||
routes::get_hexagon_properties(state_hexagon_properties.clone(), ext, query)
|
||||
}),
|
||||
get(move |ext, query| routes::get_hexagon_properties(s11.load_state(), ext, query)),
|
||||
)
|
||||
.route(
|
||||
"/api/hexagon-stats",
|
||||
get(move |ext, query| {
|
||||
routes::get_hexagon_stats(state_hexagon_stats.clone(), ext, query)
|
||||
}),
|
||||
get(move |ext, query| routes::get_hexagon_stats(s12.load_state(), ext, query)),
|
||||
)
|
||||
.route(
|
||||
"/api/postcode-stats",
|
||||
get(move |ext, query| {
|
||||
routes::get_postcode_stats(state_postcode_stats.clone(), ext, query)
|
||||
}),
|
||||
get(move |ext, query| routes::get_postcode_stats(s13.load_state(), ext, query)),
|
||||
)
|
||||
.route(
|
||||
"/api/postcode-properties",
|
||||
get(move |ext, query| {
|
||||
routes::get_postcode_properties(state_postcode_properties.clone(), ext, query)
|
||||
}),
|
||||
get(move |ext, query| routes::get_postcode_properties(s14.load_state(), ext, query)),
|
||||
)
|
||||
.route(
|
||||
"/api/screenshot",
|
||||
get(move |headers, query| {
|
||||
routes::get_screenshot(state_screenshot.clone(), headers, query)
|
||||
}),
|
||||
get(move |headers, query| routes::get_screenshot(s15.load_state(), headers, query)),
|
||||
)
|
||||
.route(
|
||||
"/api/export",
|
||||
get(move |headers, ext, query| {
|
||||
routes::get_export(state_export.clone(), headers, ext, query)
|
||||
routes::get_export(s16.load_state(), headers, ext, query)
|
||||
})
|
||||
.layer(ConcurrencyLimitLayer::new(3)),
|
||||
)
|
||||
.route("/api/me", get(routes::get_me))
|
||||
.route(
|
||||
"/api/shorten",
|
||||
post(move |body| routes::post_shorten(state_shorten.clone(), body)),
|
||||
post(move |body| routes::post_shorten(s17.load_state(), body)),
|
||||
)
|
||||
.route(
|
||||
"/api/ai-filters",
|
||||
post(move |ext, body| routes::post_ai_filters(state_ai_filters.clone(), ext, body))
|
||||
post(move |ext, body| routes::post_ai_filters(s18.load_state(), ext, body))
|
||||
.layer(ConcurrencyLimitLayer::new(5)),
|
||||
)
|
||||
.route(
|
||||
"/api/streetview",
|
||||
get(move |query| routes::get_streetview(state_streetview.clone(), query)),
|
||||
get(move |query| routes::get_streetview(s19.load_state(), query)),
|
||||
)
|
||||
.route(
|
||||
"/api/newsletter",
|
||||
patch(move |ext, body| routes::patch_newsletter(state_newsletter.clone(), ext, body)),
|
||||
patch(move |ext, body| routes::patch_newsletter(s20.load_state(), ext, body)),
|
||||
)
|
||||
.route(
|
||||
"/api/pricing",
|
||||
get(move || routes::get_pricing(state_pricing.clone())),
|
||||
get(move || routes::get_pricing(s21.load_state())),
|
||||
)
|
||||
.route(
|
||||
"/api/checkout",
|
||||
post(move |ext, body| routes::post_checkout(state_checkout.clone(), ext, body))
|
||||
post(move |ext, body| routes::post_checkout(s22.load_state(), ext, body))
|
||||
.layer(ConcurrencyLimitLayer::new(10)),
|
||||
)
|
||||
.route(
|
||||
"/api/stripe-webhook",
|
||||
post(move |headers, body| {
|
||||
routes::post_stripe_webhook(state_stripe_webhook.clone(), headers, body)
|
||||
}),
|
||||
post(move |headers, body| routes::post_stripe_webhook(s23.load_state(), headers, body)),
|
||||
)
|
||||
.route(
|
||||
"/api/invites",
|
||||
get(move |ext| routes::get_invites(state_invites_list.clone(), ext)).post(
|
||||
move |ext, body| routes::post_invites(state_invites_create.clone(), ext, body),
|
||||
),
|
||||
get(move |ext| routes::get_invites(s24.load_state(), ext))
|
||||
.post(move |ext, body| routes::post_invites(s25.load_state(), ext, body)),
|
||||
)
|
||||
.route(
|
||||
"/api/invite/{code}",
|
||||
get(move |ext, path| routes::get_invite(state_invite_get.clone(), ext, path)),
|
||||
get(move |ext, path| routes::get_invite(s26.load_state(), ext, path)),
|
||||
)
|
||||
.route(
|
||||
"/api/redeem-invite",
|
||||
post(move |ext, body| {
|
||||
routes::post_redeem_invite(state_redeem_invite.clone(), ext, body)
|
||||
}),
|
||||
post(move |ext, body| routes::post_redeem_invite(s27.load_state(), ext, body)),
|
||||
)
|
||||
.route(
|
||||
"/s/{code}",
|
||||
get(move |path| routes::get_short_url(state_short_url.clone(), path)),
|
||||
get(move |path| routes::get_short_url(s28.load_state(), path)),
|
||||
)
|
||||
.route(
|
||||
"/api/telemetry",
|
||||
post(move |ext, headers, body| {
|
||||
let _ = state_telemetry.clone();
|
||||
let _ = s29.load_state();
|
||||
routes::post_telemetry(ext, headers, body)
|
||||
}),
|
||||
)
|
||||
.route(
|
||||
"/api/reload",
|
||||
post(move || routes::post_reload(s_reload.clone())),
|
||||
);
|
||||
|
||||
// Add tile routes
|
||||
let reader_tile = tile_reader.clone();
|
||||
let reader_style = tile_reader.clone();
|
||||
let public_url_tiles = state.public_url.clone();
|
||||
let public_url_tiles = initial_state.public_url.clone();
|
||||
let api = api
|
||||
.route(
|
||||
"/api/tiles/{z}/{x}/{y}",
|
||||
|
|
@ -609,7 +591,7 @@ async fn main() -> anyhow::Result<()> {
|
|||
)
|
||||
.route(
|
||||
"/pb/{*rest}",
|
||||
any(move |req| routes::proxy_to_pocketbase(state_pb.clone(), req)),
|
||||
any(move |req| routes::proxy_to_pocketbase(s_pb.load_state(), req)),
|
||||
);
|
||||
|
||||
let app = if let Some(ref dist) = cli.dist {
|
||||
|
|
@ -621,7 +603,7 @@ async fn main() -> anyhow::Result<()> {
|
|||
.layer(middleware::from_fn(auth::auth_middleware))
|
||||
.layer(middleware::from_fn(
|
||||
move |req: axum::extract::Request, next: middleware::Next| {
|
||||
let st = state_crawler.clone();
|
||||
let st = s_crawler.load_state();
|
||||
async move {
|
||||
// Inject state into request extensions for auth + OG middleware
|
||||
let (mut parts, body) = req.into_parts();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue