Use new LocalRSSDataSource in LocalFeedRepository

This commit is contained in:
Shinokuni 2020-09-17 22:15:33 +02:00
parent 838768800a
commit 82c29d0732
3 changed files with 64 additions and 121 deletions

View File

@ -30,6 +30,7 @@ class LocalRSSDataSource(private val httpClient: OkHttpClient) {
* @param withItems parse items with their feed * @param withItems parse items with their feed
* @return a Feed object with its items if specified by [withItems] * @return a Feed object with its items if specified by [withItems]
*/ */
@Throws(ParseException::class, UnknownFormatException::class, NetworkErrorException::class, IOException::class)
@WorkerThread @WorkerThread
fun queryRSSResource(url: String, headers: Headers?, withItems: Boolean): Pair<Feed, List<Item>>? { fun queryRSSResource(url: String, headers: Headers?, withItems: Boolean): Pair<Feed, List<Item>>? {
val response = queryUrl(url, headers) val response = queryUrl(url, headers)

View File

@ -2,30 +2,25 @@ package com.readrops.app.repositories;
import android.accounts.NetworkErrorException; import android.accounts.NetworkErrorException;
import android.content.Context; import android.content.Context;
import android.util.Log;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.readrops.api.localfeed.LocalRSSDataSource;
import com.readrops.api.services.SyncResult;
import com.readrops.api.utils.HttpManager;
import com.readrops.api.utils.LibUtils;
import com.readrops.api.utils.ParseException;
import com.readrops.api.utils.UnknownFormatException;
import com.readrops.app.utils.FeedInsertionResult; import com.readrops.app.utils.FeedInsertionResult;
import com.readrops.app.utils.HtmlParser; import com.readrops.app.utils.HtmlParser;
import com.readrops.app.utils.ParsingResult; import com.readrops.app.utils.ParsingResult;
import com.readrops.app.utils.SharedPreferencesManager; import com.readrops.app.utils.SharedPreferencesManager;
import com.readrops.app.utils.Utils; import com.readrops.app.utils.Utils;
import com.readrops.app.utils.matchers.FeedMatcher;
import com.readrops.app.utils.matchers.ItemMatcher;
import com.readrops.db.entities.Feed; import com.readrops.db.entities.Feed;
import com.readrops.db.entities.Item; import com.readrops.db.entities.Item;
import com.readrops.db.entities.account.Account; import com.readrops.db.entities.account.Account;
import com.readrops.api.localfeed.AFeed;
import com.readrops.api.localfeed.RSSQuery;
import com.readrops.api.localfeed.RSSQueryResult;
import com.readrops.api.localfeed.atom.ATOMFeed;
import com.readrops.api.localfeed.json.JSONFeed;
import com.readrops.api.localfeed.rss.RSSFeed;
import com.readrops.api.services.SyncResult;
import com.readrops.api.utils.LibUtils;
import com.readrops.api.utils.ParseException;
import com.readrops.api.utils.UnknownFormatException;
import org.jsoup.Jsoup; import org.jsoup.Jsoup;
@ -33,20 +28,24 @@ import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.List; import java.util.List;
import io.reactivex.Observable; import io.reactivex.Observable;
import io.reactivex.Single; import io.reactivex.Single;
import kotlin.Pair;
import okhttp3.Headers;
public class LocalFeedRepository extends ARepository<Void> { public class LocalFeedRepository extends ARepository<Void> {
private static final String TAG = LocalFeedRepository.class.getSimpleName(); private static final String TAG = LocalFeedRepository.class.getSimpleName();
private LocalRSSDataSource dataSource;
public LocalFeedRepository(@NonNull Context context, @Nullable Account account) { public LocalFeedRepository(@NonNull Context context, @Nullable Account account) {
super(context, account); super(context, account);
syncResult = new SyncResult(); syncResult = new SyncResult();
dataSource = new LocalRSSDataSource(HttpManager.getInstance().getOkHttpClient());
} }
@Override @Override
@ -64,47 +63,31 @@ public class LocalFeedRepository extends ARepository<Void> {
return Observable.create(emitter -> { return Observable.create(emitter -> {
List<Feed> feedList; List<Feed> feedList;
if (feeds == null || feeds.size() == 0) if (feeds == null || feeds.isEmpty()) {
feedList = database.feedDao().getFeeds(account.getId()); feedList = database.feedDao().getFeeds(account.getId());
else } else {
feedList = new ArrayList<>(feeds); feedList = feeds;
}
RSSQuery rssQuery = new RSSQuery();
List<FeedInsertionResult> syncErrors = new ArrayList<>();
for (Feed feed : feedList) { for (Feed feed : feedList) {
emitter.onNext(feed); emitter.onNext(feed);
FeedInsertionResult syncError = new FeedInsertionResult();
try { try {
HashMap<String, String> headers = new HashMap<>(); Headers.Builder headers = new Headers.Builder();
if (feed.getEtag() != null) if (feed.getEtag() != null) {
headers.put(LibUtils.IF_NONE_MATCH_HEADER, feed.getEtag()); headers.add(LibUtils.IF_NONE_MATCH_HEADER, feed.getEtag());
if (feed.getLastModified() != null) }
headers.put(LibUtils.IF_MODIFIED_HEADER, feed.getLastModified()); if (feed.getLastModified() != null) {
headers.add(LibUtils.IF_MODIFIED_HEADER, feed.getLastModified());
}
RSSQueryResult queryResult = rssQuery.queryUrl(feed.getUrl(), headers); Pair<Feed, List<Item>> pair = dataSource.queryRSSResource(feed.getUrl(), headers.build(), true);
if (queryResult != null && queryResult.getException() == null)
insertNewItems(queryResult.getFeed(), queryResult.getRssType());
else if (queryResult != null && queryResult.getException() != null) {
Exception e = queryResult.getException();
if (e instanceof UnknownFormatException) if (pair != null) {
syncError.setInsertionError(FeedInsertionResult.FeedInsertionError.FORMAT_ERROR); insertNewItems(feed, pair.getSecond());
else if (e instanceof NetworkErrorException)
syncError.setInsertionError(FeedInsertionResult.FeedInsertionError.NETWORK_ERROR);
syncError.setFeed(feed);
syncErrors.add(syncError);
} }
} catch (Exception e) { } catch (Exception e) {
if (e instanceof IOException) Log.d(TAG, "sync: " + e.getMessage());
syncError.setInsertionError(FeedInsertionResult.FeedInsertionError.NETWORK_ERROR);
else
syncError.setInsertionError(FeedInsertionResult.FeedInsertionError.PARSE_ERROR);
syncError.setFeed(feed);
syncErrors.add(syncError);
} }
} }
@ -121,28 +104,22 @@ public class LocalFeedRepository extends ARepository<Void> {
FeedInsertionResult insertionResult = new FeedInsertionResult(); FeedInsertionResult insertionResult = new FeedInsertionResult();
try { try {
RSSQuery rssNet = new RSSQuery(); Pair<Feed, List<Item>> pair = dataSource.queryRSSResource(parsingResult.getUrl(),
RSSQueryResult queryResult = rssNet.queryUrl(parsingResult.getUrl(), new HashMap<>()); null, false);
Feed feed = insertFeed(pair.getFirst(), parsingResult);
if (queryResult != null && queryResult.getException() == null) { if (feed != null) {
Feed feed = insertFeed(queryResult.getFeed(), queryResult.getRssType(), parsingResult); insertionResult.setFeed(feed);
if (feed != null) {
insertionResult.setFeed(feed);
insertionResult.setParsingResult(parsingResult);
insertionResults.add(insertionResult);
}
} else if (queryResult != null && queryResult.getException() != null) {
insertionResult.setParsingResult(parsingResult);
insertionResult.setInsertionError(getErrorFromException(queryResult.getException()));
insertionResults.add(insertionResult);
} }
} catch (ParseException e) {
insertionResult.setInsertionError(FeedInsertionResult.FeedInsertionError.PARSE_ERROR);
} catch (UnknownFormatException e) {
insertionResult.setInsertionError(FeedInsertionResult.FeedInsertionError.FORMAT_ERROR);
} catch (NetworkErrorException | IOException e) {
insertionResult.setInsertionError(FeedInsertionResult.FeedInsertionError.NETWORK_ERROR);
} catch (Exception e) { } catch (Exception e) {
if (e instanceof IOException) insertionResult.setInsertionError(FeedInsertionResult.FeedInsertionError.UNKNOWN_ERROR);
insertionResult.setInsertionError(FeedInsertionResult.FeedInsertionError.NETWORK_ERROR); } finally {
else
insertionResult.setInsertionError(FeedInsertionResult.FeedInsertionError.PARSE_ERROR);
insertionResult.setParsingResult(parsingResult); insertionResult.setParsingResult(parsingResult);
insertionResults.add(insertionResult); insertionResults.add(insertionResult);
} }
@ -152,67 +129,38 @@ public class LocalFeedRepository extends ARepository<Void> {
}); });
} }
private void insertNewItems(AFeed feed, RSSQuery.RSSType type) throws ParseException { @SuppressWarnings("SimplifyStreamApiCallChains")
Feed dbFeed; private void insertNewItems(Feed feed, List<Item> items) {
List<Item> items; database.feedDao().updateHeaders(feed.getEtag(), feed.getLastModified(), feed.getId());
switch (type) {
case RSS_2:
dbFeed = database.feedDao().getFeedByUrl(((RSSFeed) feed).getChannel().getFeedUrl(), account.getId());
items = ItemMatcher.itemsFromRSS(((RSSFeed) feed).getChannel().getItems(), dbFeed);
break;
case RSS_ATOM:
dbFeed = database.feedDao().getFeedByUrl(((ATOMFeed) feed).getUrl(), account.getId());
items = ItemMatcher.itemsFromATOM(((ATOMFeed) feed).getEntries(), dbFeed);
break;
case RSS_JSON:
dbFeed = database.feedDao().getFeedByUrl(((JSONFeed) feed).getFeedUrl(), account.getId());
items = ItemMatcher.itemsFromJSON(((JSONFeed) feed).getItems(), dbFeed);
break;
default:
throw new IllegalArgumentException("Unknown RSS type");
}
database.feedDao().updateHeaders(dbFeed.getEtag(), dbFeed.getLastModified(), dbFeed.getId());
Collections.sort(items, Item::compareTo); Collections.sort(items, Item::compareTo);
int maxItems = Integer.parseInt(SharedPreferencesManager.readString(context, SharedPreferencesManager.SharedPrefKey.ITEMS_TO_PARSE_MAX_NB)); int maxItems = Integer.parseInt(SharedPreferencesManager.readString(context,
if (maxItems > 0 && items.size() > maxItems) SharedPreferencesManager.SharedPrefKey.ITEMS_TO_PARSE_MAX_NB));
if (maxItems > 0 && items.size() > maxItems) {
items = items.subList(items.size() - maxItems, items.size()); items = items.subList(items.size() - maxItems, items.size());
insertItems(items, dbFeed);
}
private Feed insertFeed(AFeed feed, RSSQuery.RSSType type, ParsingResult parsingResult) {
Feed dbFeed;
switch (type) {
case RSS_2:
dbFeed = FeedMatcher.feedFromRSS((RSSFeed) feed);
break;
case RSS_ATOM:
dbFeed = FeedMatcher.feedFromATOM((ATOMFeed) feed);
break;
case RSS_JSON:
dbFeed = FeedMatcher.feedFromJSON((JSONFeed) feed);
break;
default:
throw new IllegalArgumentException("Unknown RSS type");
} }
dbFeed.setFolderId(parsingResult.getFolderId()); items.stream().forEach(item -> item.setFeedId(feed.getId()));
insertItems(items, feed);
}
if (database.feedDao().feedExists(dbFeed.getUrl(), account.getId())) private Feed insertFeed(Feed feed, ParsingResult parsingResult) {
feed.setFolderId(parsingResult.getFolderId());
if (database.feedDao().feedExists(feed.getUrl(), account.getId())) {
return null; // feed already inserted return null; // feed already inserted
}
setFeedColors(dbFeed); setFeedColors(feed);
dbFeed.setAccountId(account.getId()); feed.setAccountId(account.getId());
// we need empty headers to query the feed just after, without any 304 result // we need empty headers to query the feed just after, without any 304 result
dbFeed.setEtag(null); feed.setEtag(null);
dbFeed.setLastModified(null); feed.setLastModified(null);
dbFeed.setId((int) (database.feedDao().compatInsert(dbFeed))); feed.setId((int) (database.feedDao().compatInsert(feed)));
return dbFeed; return feed;
} }
private void insertItems(Collection<Item> items, Feed feed) { private void insertItems(Collection<Item> items, Feed feed) {
@ -253,13 +201,4 @@ public class LocalFeedRepository extends ARepository<Void> {
syncResult.getItems().addAll(itemsToInsert); syncResult.getItems().addAll(itemsToInsert);
database.itemDao().insert(itemsToInsert); database.itemDao().insert(itemsToInsert);
} }
private FeedInsertionResult.FeedInsertionError getErrorFromException(Exception e) {
if (e instanceof UnknownFormatException)
return FeedInsertionResult.FeedInsertionError.FORMAT_ERROR;
else if (e instanceof NetworkErrorException)
return FeedInsertionResult.FeedInsertionError.NETWORK_ERROR;
else
return FeedInsertionResult.FeedInsertionError.UNKNOWN_ERROR;
}
} }

View File

@ -29,6 +29,9 @@ public abstract class FeedDao implements BaseDao<Feed> {
@Query("Select * from Feed Where id = :feedId") @Query("Select * from Feed Where id = :feedId")
public abstract Feed getFeedById(int feedId); public abstract Feed getFeedById(int feedId);
@Query("Select id From Feed Where url = :url and account_id = :accountId")
public abstract int getFeedIdByUrl(String url, int accountId);
@Query("Select case When :feedUrl In (Select url from Feed Where account_id = :accountId) Then 1 else 0 end") @Query("Select case When :feedUrl In (Select url from Feed Where account_id = :accountId) Then 1 else 0 end")
public abstract boolean feedExists(String feedUrl, int accountId); public abstract boolean feedExists(String feedUrl, int accountId);