feedsignal/crates/web/src/server/services/feeds.rs
Austin Schaefer 44b9724645
All checks were successful
CI / check (pull_request) Successful in 8m13s
CI / test (pull_request) Successful in 2m36s
CI / audit (pull_request) Successful in 11s
Split web crate into layered modules (api/services/jobs/view)
Separates controllers (api/, the #[server] endpoints) from business
services (server/services/), background scheduling (server/jobs/,
renamed from pipeline.rs), infra bootstrap/config (server/mod.rs,
server/config.rs), and view components (app/), each one file per
responsibility instead of the previous server.rs/app.rs/pipeline.rs
grab-bags.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LoXS1ERDGC1P189RqmUxAF
2026-09-03 12:03:15 +02:00

33 lines
1.3 KiB
Rust

use anyhow::Result;
use feedsignal_db::Db;
use uuid::Uuid;
/// Subscribes to a feed by URL: registers it (or updates its title if
/// already subscribed) and does an immediate first fetch so the reader
/// isn't empty until the next scheduled poll. Returns the number of
/// articles pulled in on this fetch.
///
/// Fetches under a throwaway id before writing anything, so there's exactly
/// one write to the `feeds` table (`upsert_feed` is the single source of
/// truth for the real id — the existing one on a re-subscribe, a fresh one
/// otherwise) and no half-registered row left behind if the fetch fails
/// (e.g. the URL is well-formed but points at nothing, or the feed no
/// longer exists — `fetch_feed` surfaces both as an `Err` via
/// `error_for_status`/feed-rs parse failure, which becomes the error
/// message shown in the subscribe form).
pub async fn subscribe(db: Db, url: String) -> Result<usize> {
anyhow::ensure!(!url.trim().is_empty(), "feed URL is required");
let url = url.trim();
let (title, mut articles) = feedsignal_feeds::fetch_feed(url, Uuid::new_v4()).await?;
let feed_id = db.upsert_feed(url, &title).await?;
for article in &mut articles {
article.feed_id = feed_id;
}
let count = articles.len();
for article in &articles {
db.insert_article(article).await?;
}
Ok(count)
}