Add method for adding an RSS feed from an input stream.

This commit is contained in:
akwizgran
2023-01-24 13:57:44 +00:00
parent 8f7bb9d26b
commit 28a747f7f3
5 changed files with 103 additions and 12 deletions

View File

@@ -6,6 +6,7 @@ import org.briarproject.bramble.api.sync.ClientId;
import org.briarproject.nullsafety.NotNullByDefault; import org.briarproject.nullsafety.NotNullByDefault;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.util.List; import java.util.List;
@NotNullByDefault @NotNullByDefault
@@ -22,10 +23,17 @@ public interface FeedManager {
int MAJOR_VERSION = 0; int MAJOR_VERSION = 0;
/** /**
* Adds an RSS feed as a new dedicated blog. * Adds an RSS feed as a new dedicated blog, or updates the existing blog
* if a blog for the feed already exists.
*/ */
Feed addFeed(String url) throws DbException, IOException; Feed addFeed(String url) throws DbException, IOException;
/**
* Adds an RSS feed as a new dedicated blog, or updates the existing blog
* if a blog for the feed already exists.
*/
Feed addFeed(InputStream in) throws DbException, IOException;
/** /**
* Removes an RSS feed. * Removes an RSS feed.
*/ */

View File

@@ -6,13 +6,15 @@ import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.data.BdfDictionary; import org.briarproject.bramble.api.data.BdfDictionary;
import org.briarproject.briar.api.feed.Feed; import org.briarproject.briar.api.feed.Feed;
import javax.annotation.Nullable;
interface FeedFactory { interface FeedFactory {
/** /**
* Create a new feed based on the feed url * Create a new feed based on the feed url
* and the metadata of an existing {@link SyndFeed}. * and the metadata of an existing {@link SyndFeed}.
*/ */
Feed createFeed(String url, SyndFeed sf); Feed createFeed(@Nullable String url, SyndFeed sf);
/** /**
* Creates a new updated feed, based on the given existing feed, * Creates a new updated feed, based on the given existing feed,

View File

@@ -18,6 +18,7 @@ import org.briarproject.briar.api.blog.BlogFactory;
import org.briarproject.briar.api.feed.Feed; import org.briarproject.briar.api.feed.Feed;
import org.briarproject.briar.api.feed.RssProperties; import org.briarproject.briar.api.feed.RssProperties;
import javax.annotation.Nullable;
import javax.inject.Inject; import javax.inject.Inject;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
@@ -51,7 +52,7 @@ class FeedFactoryImpl implements FeedFactory {
} }
@Override @Override
public Feed createFeed(String url, SyndFeed sf) { public Feed createFeed(@Nullable String url, SyndFeed sf) {
String title = sf.getTitle(); String title = sf.getTitle();
if (title == null) title = "RSS"; if (title == null) title = "RSS";
else title = truncateUtf8(title, MAX_AUTHOR_NAME_LENGTH); else title = truncateUtf8(title, MAX_AUTHOR_NAME_LENGTH);

View File

@@ -56,6 +56,7 @@ import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe; import javax.annotation.concurrent.ThreadSafe;
import javax.inject.Inject; import javax.inject.Inject;
@@ -68,6 +69,7 @@ import static java.util.Collections.singletonList;
import static java.util.Collections.sort; import static java.util.Collections.sort;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger; import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.IoUtils.tryToClose;
import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty; import static org.briarproject.bramble.util.StringUtils.isNullOrEmpty;
import static org.briarproject.bramble.util.StringUtils.truncateUtf8; import static org.briarproject.bramble.util.StringUtils.truncateUtf8;
@@ -170,7 +172,19 @@ class FeedManagerImpl implements FeedManager, EventListener, OpenDatabaseHook,
@Override @Override
public Feed addFeed(String url) throws DbException, IOException { public Feed addFeed(String url) throws DbException, IOException {
// fetch feed to get posts and metadata // fetch feed to get posts and metadata
SyndFeed sf = fetchSyndFeed(url); SyndFeed sf = fetchAndCleanFeed(url);
return addFeed(url, sf);
}
@Override
public Feed addFeed(InputStream in) throws DbException, IOException {
// fetch feed to get posts and metadata
SyndFeed sf = fetchAndCleanFeed(in);
return addFeed(null, sf);
}
private Feed addFeed(@Nullable String url, SyndFeed sf) throws DbException {
// extract properties from the feed
RssProperties properties = new RssProperties(url, sf.getTitle(), RssProperties properties = new RssProperties(url, sf.getTitle(),
sf.getDescription(), sf.getAuthor(), sf.getLink(), sf.getUri()); sf.getDescription(), sf.getAuthor(), sf.getLink(), sf.getUri());
@@ -323,7 +337,7 @@ class FeedManagerImpl implements FeedManager, EventListener, OpenDatabaseHook,
String url = feed.getProperties().getUrl(); String url = feed.getProperties().getUrl();
if (url == null) continue; if (url == null) continue;
// fetch and clean feed // fetch and clean feed
SyndFeed sf = fetchSyndFeed(url); SyndFeed sf = fetchAndCleanFeed(url);
// sort and add new entries // sort and add new entries
long lastEntryTime = postFeedEntries(feed, sf.getEntries()); long lastEntryTime = postFeedEntries(feed, sf.getEntries());
updatedFeeds.add( updatedFeeds.add(
@@ -342,11 +356,17 @@ class FeedManagerImpl implements FeedManager, EventListener, OpenDatabaseHook,
LOG.info("Done updating RSS feeds"); LOG.info("Done updating RSS feeds");
} }
private SyndFeed fetchSyndFeed(String url) throws IOException { private SyndFeed fetchAndCleanFeed(String url) throws IOException {
// fetch feed return fetchAndCleanFeed(getFeedInputStream(url));
InputStream stream = getFeedInputStream(url); }
SyndFeed sf = getSyndFeed(stream);
stream.close(); private SyndFeed fetchAndCleanFeed(InputStream in) throws IOException {
SyndFeed sf;
try {
sf = getSyndFeed(in);
} finally {
tryToClose(in, LOG, WARNING);
}
// clean title // clean title
String title = sf.getTitle(); String title = sf.getTitle();

View File

@@ -28,6 +28,7 @@ import org.briarproject.briar.api.feed.RssProperties;
import org.jmock.Expectations; import org.jmock.Expectations;
import org.junit.Test; import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
@@ -38,6 +39,7 @@ import okhttp3.OkHttpClient;
import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer; import okhttp3.mockwebserver.MockWebServer;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Collections.singletonList; import static java.util.Collections.singletonList;
import static okhttp3.mockwebserver.SocketPolicy.DISCONNECT_DURING_RESPONSE_BODY; import static okhttp3.mockwebserver.SocketPolicy.DISCONNECT_DURING_RESPONSE_BODY;
import static org.briarproject.bramble.test.TestUtils.getGroup; import static org.briarproject.bramble.test.TestUtils.getGroup;
@@ -46,6 +48,7 @@ import static org.briarproject.bramble.test.TestUtils.getMessage;
import static org.briarproject.briar.api.feed.FeedConstants.KEY_FEEDS; import static org.briarproject.briar.api.feed.FeedConstants.KEY_FEEDS;
import static org.briarproject.briar.api.feed.FeedManager.CLIENT_ID; import static org.briarproject.briar.api.feed.FeedManager.CLIENT_ID;
import static org.briarproject.briar.api.feed.FeedManager.MAJOR_VERSION; import static org.briarproject.briar.api.feed.FeedManager.MAJOR_VERSION;
import static org.hamcrest.Matchers.nullValue;
public class FeedManagerImplTest extends BrambleMockTestCase { public class FeedManagerImplTest extends BrambleMockTestCase {
@@ -183,7 +186,7 @@ public class FeedManagerImplTest extends BrambleMockTestCase {
} }
@Test @Test
public void testAddNewFeed() throws Exception { public void testAddNewFeedFromUrl() throws Exception {
// Fetching and parsing the feed will succeed; there are no entries // Fetching and parsing the feed will succeed; there are no entries
String feedXml = createRssFeedXml(); String feedXml = createRssFeedXml();
@@ -223,7 +226,7 @@ public class FeedManagerImplTest extends BrambleMockTestCase {
} }
@Test @Test
public void testAddExistingFeed() throws Exception { public void testAddExistingFeedFromUrl() throws Exception {
// Fetching and parsing the feed will succeed; there are no entries // Fetching and parsing the feed will succeed; there are no entries
String feedXml = createRssFeedXml(); String feedXml = createRssFeedXml();
@@ -248,6 +251,63 @@ public class FeedManagerImplTest extends BrambleMockTestCase {
feedManager.addFeed(url); feedManager.addFeed(url);
} }
@Test
public void testAddNewFeedFromInputStream() throws Exception {
// Reading and parsing the feed will succeed; there are no entries
String feedXml = createRssFeedXml();
Feed newFeed = createFeed(null, blog);
Group existingBlogGroup = getGroup(BlogManager.CLIENT_ID,
BlogManager.MAJOR_VERSION);
Blog existingBlog = new Blog(existingBlogGroup, localAuthor, true);
Feed existingFeed = createFeed(null, existingBlog);
expectGetFeeds(existingFeed);
context.checking(new DbExpectations() {{
// The added feed doesn't match any existing feed
oneOf(feedMatcher).findMatchingFeed(with(any(RssProperties.class)),
with(singletonList(existingFeed)));
will(returnValue(null));
// Create the new feed
oneOf(feedFactory).createFeed(with(nullValue(String.class)),
with(any(SyndFeed.class)));
will(returnValue(newFeed));
// Add the new feed to the list of feeds
Transaction txn = new Transaction(null, false);
oneOf(db).transaction(with(false), withDbRunnable(txn));
oneOf(blogManager).addBlog(txn, blog);
expectGetFeeds(txn, existingFeed);
expectStoreFeeds(txn, existingFeed, newFeed);
}});
expectUpdateFeedNoEntries(newFeed);
expectGetAndStoreFeeds(existingFeed, newFeed);
feedManager.addFeed(new ByteArrayInputStream(feedXml.getBytes(UTF_8)));
}
@Test
public void testAddExistingFeedFromInputStream() throws Exception {
// Reading and parsing the feed will succeed; there are no entries
String feedXml = createRssFeedXml();
Feed newFeed = createFeed(null, blog);
expectGetFeeds(newFeed);
context.checking(new DbExpectations() {{
// The added feed matches an existing feed
oneOf(feedMatcher).findMatchingFeed(with(any(RssProperties.class)),
with(singletonList(newFeed)));
will(returnValue(newFeed));
}});
expectUpdateFeedNoEntries(newFeed);
expectGetAndStoreFeeds(newFeed);
feedManager.addFeed(new ByteArrayInputStream(feedXml.getBytes(UTF_8)));
}
private Feed createFeed(String url, Blog blog) { private Feed createFeed(String url, Blog blog) {
RssProperties properties = new RssProperties(url, RssProperties properties = new RssProperties(url,
null, null, null, null, null); null, null, null, null, null);