From 9b5a8321f0a723cc2a4357fd10e04e2ee770a11e Mon Sep 17 00:00:00 2001 From: Jack Platten Date: Tue, 10 Mar 2026 11:47:18 -0700 Subject: [PATCH] backend cachebusting --- src/main.rs | 55 ++++++++++++++++++++++++++++++++++++----------- src/rss_poller.rs | 55 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 12 deletions(-) diff --git a/src/main.rs b/src/main.rs index 33d4ff3..31c1c92 100644 --- a/src/main.rs +++ b/src/main.rs @@ -57,26 +57,57 @@ fn index() -> &'static str { #[get("/slug/")] async fn post_meta(mut db: Connection, slug: &str) -> Option { - sqlx::query("SELECT * FROM posts WHERE slug = $1") + let db_result = sqlx::query("SELECT * FROM posts WHERE slug = $1") .bind(slug) .fetch_one(&mut **db) - .await - .map(|row| { + .await; + + match db_result { + Ok(row) => { let meta = Meta { id: row.get(0), slug: row.get(1), rkey: row.get(2), time_us: row.get(3), }; - - json![{ - "status" : "success", - "data": { - "post": meta - } - }] - }) - .ok() + Some(json![{ + "status": "success", + "data": {"post": meta} + }]) + } + Err(_) => { + // Not in DB — check the live RSS feed + let (rkey, time_us) = rss_poller::lookup_slug_in_rss(slug).await?; + + // Insert; ignore conflicts in case the background poller raced us + let _ = sqlx::query( + "INSERT INTO posts (slug, rkey, time_us) VALUES ($1, $2, $3) ON CONFLICT (slug) DO NOTHING" + ) + .bind(slug) + .bind(&rkey) + .bind(&time_us) + .execute(&mut **db) + .await; + + sqlx::query("SELECT * FROM posts WHERE slug = $1") + .bind(slug) + .fetch_one(&mut **db) + .await + .map(|row| { + let meta = Meta { + id: row.get(0), + slug: row.get(1), + rkey: row.get(2), + time_us: row.get(3), + }; + json![{ + "status": "success", + "data": {"post": meta} + }] + }) + .ok() + } + } } #[get("/slug")] diff --git a/src/rss_poller.rs b/src/rss_poller.rs index d08765a..998ea07 100644 --- a/src/rss_poller.rs +++ b/src/rss_poller.rs @@ -143,6 +143,61 @@ async fn poll_rss(pool: &sqlx::Pool, config: &PollerConfig) -> R Ok(()) } +/// Look up a specific slug in the RSS feed on demand. +/// Returns `(rkey, time_us)` if the slug is found, `None` otherwise. +pub async fn lookup_slug_in_rss(slug: &str) -> Option<(String, String)> { + let config = match Config::figment().extract::() { + Ok(c) => c, + Err(e) => { + log::error!("[rss] Failed to load config: {}", e); + return None; + } + }; + + let channel = match fetch_rss(&config.poster_handle).await { + Ok(c) => c, + Err(e) => { + log::error!("[rss] Failed to fetch RSS for on-demand lookup: {}", e); + return None; + } + }; + + for item in channel.items() { + let guid = match item.guid() { + Some(g) => g.value(), + None => continue, + }; + + let rkey = match extract_rkey(guid) { + Some(r) => r, + None => continue, + }; + + let description = match item.description() { + Some(d) => d, + None => continue, + }; + + let urls = find_blog_urls(description, &config.target_emoji, &config.blog_domain); + + for url in &urls { + if let Some(found_slug) = extract_slug_from_url(url, &config.blog_domain) { + if found_slug == slug { + let time_us = item + .pub_date() + .and_then(|date_str| chrono::DateTime::parse_from_rfc2822(date_str).ok()) + .map(|dt| dt.timestamp_micros().to_string()) + .unwrap_or_else(|| chrono::Utc::now().timestamp_micros().to_string()); + log::info!("[rss] On-demand lookup found slug={} rkey={}", slug, rkey); + return Some((rkey, time_us)); + } + } + } + } + + None +} + /// Background task that polls RSS every 15 minutes pub async fn rss_polling_task(pool: sqlx::Pool) { let config = match Config::figment().extract::() { -- 2.51.2