Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(filters): add convert_to filter for converting feed format #68

Merged
merged 11 commits into from
Mar 5, 2024
14 changes: 14 additions & 0 deletions fixtures/minimal_rss_20.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<rss version="2.0">
<channel>
<title>Test</title>
<link>http://example.com</link>
<description>Test description</description>

<item>
<title>Item 1</title>
<guid isPermaLink="false">http://example.com/item1</guid>
<link>http://example.com/item1</link>
<description>Item 1 description</description>
</item>
</channel>
</rss>
39 changes: 39 additions & 0 deletions fixtures/sample_atom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<!-- Example taken from https://www.ibm.com/docs/en/baw/22.x?topic=formats-atom-feed-format -->
<title>Example Feed</title>
<subtitle>A subtitle.</subtitle>
<link href="http://example.org/feed/" rel="self"/>
<link href="http://example.org/"/>
<updated>2003-12-13T18:30:02Z</updated>
<author>
<name>John Doe</name>
<email>johndoe@example.com</email>
</author>
<id>urn:uuid:60a76c80-d399-11d9-b91C-0003939e0af6</id>
<entry>
<content type="text/xml">
<p:Customer xmlns:p="http://www.ibm.com/crm" xmlns="http://www.ibm.com/crm">
<id>10</id>
</p:Customer>
</content>
<title>Atom-Powered Robots Run Amok</title>
<link href="http://example.org/2003/12/13/atom03"/>
<id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
<updated>2003-12-13T18:30:02Z</updated>
<summary>Some text.</summary>
</entry>
<entry>
<content>
<content type="text/json">
{"firstName"="John","lastName"="Doe","id"="10"}
</content>
<type>text/json</type>
</content>
<title>Atom-Powered Robots Run Amok</title>
<link href="http://example.org/2003/12/13/atom03"/>
<id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
<updated>2003-12-13T18:30:02Z</updated>
<summary>Some text.</summary>
</entry>
</feed>
File renamed without changes.
52 changes: 48 additions & 4 deletions src/feed.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
mod conversion;

use paste::paste;
use schemars::JsonSchema;
use serde::Deserialize;
Expand All @@ -10,15 +12,15 @@ use crate::source::FromScratch;
use crate::util::Error;
use crate::util::Result;

#[derive(Serialize, Deserialize, Clone, Debug)]
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
#[serde(untagged)]
pub enum Feed {
Rss(rss::Channel),
Atom(atom_syndication::Feed),
}

#[derive(
JsonSchema, Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Hash,
JsonSchema, Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Hash, Copy,
)]
#[serde(rename_all = "lowercase")]
pub enum FeedFormat {
Expand All @@ -29,15 +31,33 @@ pub enum FeedFormat {
}

impl Feed {
// currently only used in tests.
#[cfg(test)]
pub fn format(&self) -> FeedFormat {
match self {
Feed::Rss(_) => FeedFormat::Rss,
Feed::Atom(_) => FeedFormat::Atom,
}
}

pub fn into_format(self, format: FeedFormat) -> Self {
use conversion::W;

if self.format() == format {
return self;
}

match (self, format) {
(Feed::Rss(channel), FeedFormat::Atom) => {
let feed: atom_syndication::Feed = W(channel).into();
Feed::Atom(feed)
}
(Feed::Atom(feed), FeedFormat::Rss) => {
let channel: rss::Channel = W(feed).into();
Feed::Rss(channel)
}
(original_self, _) => original_self,
}
}

pub fn from_rss_content(content: &[u8]) -> Result<Self> {
let cursor = std::io::Cursor::new(content);
let channel = rss::Channel::read_from(cursor)?;
Expand Down Expand Up @@ -190,6 +210,30 @@ impl Feed {
}
}

#[cfg(test)]
impl TryFrom<Feed> for rss::Channel {
type Error = ();

fn try_from(feed: Feed) -> Result<Self, Self::Error> {
match feed {
Feed::Rss(channel) => Ok(channel),
_ => Err(()),
}
}
}

#[cfg(test)]
impl TryFrom<Feed> for atom_syndication::Feed {
type Error = ();

fn try_from(feed: Feed) -> Result<Self, Self::Error> {
match feed {
Feed::Atom(feed) => Ok(feed),
_ => Err(()),
}
}
}

impl From<&FromScratch> for Feed {
fn from(config: &FromScratch) -> Self {
use FeedFormat::*;
Expand Down
Loading
Loading