use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
pub const SCHEMA_VERSION: &str = "1";
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct FetchOutput {
pub schema_version: String,
pub fetched_at: String,
pub total_items: usize,
pub total_content_tokens_est: u64,
pub feeds: Vec<FeedResult>,
pub errors: Vec<ErrorObj>,
pub warnings: Vec<Warning>,
pub truncation: Option<TruncationInfo>,
}
impl FetchOutput {
pub fn new(fetched_at: String) -> Self {
Self {
schema_version: SCHEMA_VERSION.to_string(),
fetched_at,
total_items: 0,
total_content_tokens_est: 0,
feeds: Vec::new(),
errors: Vec::new(),
warnings: Vec::new(),
truncation: None,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct Warning {
pub feed_url: Option<String>,
pub code: String,
pub message: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct TruncationInfo {
pub applied_limit: Option<usize>,
pub items_content_truncated: usize,
pub items_omitted: usize,
pub estimated_tokens: Option<usize>,
pub suggestion: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum FeedStatus {
Ok,
NotModified,
Error,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct FeedResult {
pub feed_url: String,
pub status: FeedStatus,
pub from_cache: bool,
pub title: Option<String>,
pub site_url: Option<String>,
pub updated: Option<String>,
pub item_count: usize,
pub content_tokens_est_total: u64,
pub items: Vec<Item>,
pub error: Option<ErrorObj>,
}
impl FeedResult {
pub fn error(feed_url: impl Into<String>, error: ErrorObj) -> Self {
Self {
feed_url: feed_url.into(),
status: FeedStatus::Error,
from_cache: false,
title: None,
site_url: None,
updated: None,
item_count: 0,
content_tokens_est_total: 0,
items: Vec::new(),
error: Some(error),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum IdSource {
Link,
Guid,
Hash,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ContentFormat {
#[default]
Markdown,
Text,
Html,
None,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct Item {
pub id: String,
pub id_source: IdSource,
pub feed_url: String,
pub title: Option<String>,
pub url: Option<String>,
pub authors: Vec<String>,
pub published: Option<String>,
pub updated: Option<String>,
pub summary: Option<String>,
pub content: Option<String>,
pub content_format: ContentFormat,
pub content_tokens_est: u32,
pub content_truncated: bool,
pub content_hash: Option<String>,
pub categories: Vec<String>,
pub enclosures: Vec<Enclosure>,
pub guid: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct Enclosure {
pub url: String,
pub mime: Option<String>,
pub length: Option<u64>,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct ErrorObj {
pub feed_url: Option<String>,
pub code: String,
pub message: String,
#[serde(default)]
pub details: serde_json::Value,
}
impl ErrorObj {
pub fn new(code: impl Into<String>, message: impl Into<String>) -> Self {
Self {
feed_url: None,
code: code.into(),
message: message.into(),
details: serde_json::Value::Object(Default::default()),
}
}
pub fn with_feed(mut self, feed_url: impl Into<String>) -> Self {
self.feed_url = Some(feed_url.into());
self
}
pub fn with_details(mut self, details: serde_json::Value) -> Self {
self.details = details;
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct DiscoverOutput {
pub schema_version: String,
pub site_url: String,
pub feeds: Vec<DiscoveredFeed>,
}
impl DiscoverOutput {
pub fn new(site_url: impl Into<String>, feeds: Vec<DiscoveredFeed>) -> Self {
Self {
schema_version: SCHEMA_VERSION.to_string(),
site_url: site_url.into(),
feeds,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct DiscoveredFeed {
pub url: String,
pub feed_type: String,
pub title: Option<String>,
}