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
* @return a Feed object with its items if specified by [withItems]
*/
@Throws(ParseException::class, UnknownFormatException::class, NetworkErrorException::class, IOException::class)
@WorkerThread
fun queryRSSResource(url: String, headers: Headers?, withItems: Boolean): Pair<Feed, List<Item>>? {
val response = queryUrl(url, headers)

View File

@ -2,30 +2,25 @@ package com.readrops.app.repositories;
import android.accounts.NetworkErrorException;
import android.content.Context;
import android.util.Log;
import androidx.annotation.NonNull;
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.HtmlParser;
import com.readrops.app.utils.ParsingResult;
import com.readrops.app.utils.SharedPreferencesManager;
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.Item;
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;
@ -33,20 +28,24 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import io.reactivex.Observable;
import io.reactivex.Single;
import kotlin.Pair;
import okhttp3.Headers;
public class LocalFeedRepository extends ARepository<Void> {
private static final String TAG = LocalFeedRepository.class.getSimpleName();
private LocalRSSDataSource dataSource;
public LocalFeedRepository(@NonNull Context context, @Nullable Account account) {
super(context, account);
syncResult = new SyncResult();
dataSource = new LocalRSSDataSource(HttpManager.getInstance().getOkHttpClient());
}
@Override
@ -64,47 +63,31 @@ public class LocalFeedRepository extends ARepository<Void> {
return Observable.create(emitter -> {
List<Feed> feedList;
if (feeds == null || feeds.size() == 0)
if (feeds == null || feeds.isEmpty()) {
feedList = database.feedDao().getFeeds(account.getId());
else
feedList = new ArrayList<>(feeds);
RSSQuery rssQuery = new RSSQuery();
List<FeedInsertionResult> syncErrors = new ArrayList<>();
} else {
feedList = feeds;
}
for (Feed feed : feedList) {
emitter.onNext(feed);
FeedInsertionResult syncError = new FeedInsertionResult();
try {
HashMap<String, String> headers = new HashMap<>();
if (feed.getEtag() != null)
headers.put(LibUtils.IF_NONE_MATCH_HEADER, feed.getEtag());
if (feed.getLastModified() != null)
headers.put(LibUtils.IF_MODIFIED_HEADER, feed.getLastModified());
Headers.Builder headers = new Headers.Builder();
if (feed.getEtag() != null) {
headers.add(LibUtils.IF_NONE_MATCH_HEADER, feed.getEtag());
}
if (feed.getLastModified() != null) {
headers.add(LibUtils.IF_MODIFIED_HEADER, feed.getLastModified());
}
RSSQueryResult queryResult = rssQuery.queryUrl(feed.getUrl(), headers);
if (queryResult != null && queryResult.getException() == null)
insertNewItems(queryResult.getFeed(), queryResult.getRssType());
else if (queryResult != null && queryResult.getException() != null) {
Exception e = queryResult.getException();
Pair<Feed, List<Item>> pair = dataSource.queryRSSResource(feed.getUrl(), headers.build(), true);
if (e instanceof UnknownFormatException)
syncError.setInsertionError(FeedInsertionResult.FeedInsertionError.FORMAT_ERROR);
else if (e instanceof NetworkErrorException)
syncError.setInsertionError(FeedInsertionResult.FeedInsertionError.NETWORK_ERROR);
syncError.setFeed(feed);
syncErrors.add(syncError);
if (pair != null) {
insertNewItems(feed, pair.getSecond());
}
} catch (Exception e) {
if (e instanceof IOException)
syncError.setInsertionError(FeedInsertionResult.FeedInsertionError.NETWORK_ERROR);
else
syncError.setInsertionError(FeedInsertionResult.FeedInsertionError.PARSE_ERROR);
syncError.setFeed(feed);
syncErrors.add(syncError);
Log.d(TAG, "sync: " + e.getMessage());
}
}
@ -121,28 +104,22 @@ public class LocalFeedRepository extends ARepository<Void> {
FeedInsertionResult insertionResult = new FeedInsertionResult();
try {
RSSQuery rssNet = new RSSQuery();
RSSQueryResult queryResult = rssNet.queryUrl(parsingResult.getUrl(), new HashMap<>());
Pair<Feed, List<Item>> pair = dataSource.queryRSSResource(parsingResult.getUrl(),
null, false);
Feed feed = insertFeed(pair.getFirst(), parsingResult);
if (queryResult != null && queryResult.getException() == null) {
Feed feed = insertFeed(queryResult.getFeed(), queryResult.getRssType(), parsingResult);
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);
if (feed != null) {
insertionResult.setFeed(feed);
}
} 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) {
if (e instanceof IOException)
insertionResult.setInsertionError(FeedInsertionResult.FeedInsertionError.NETWORK_ERROR);
else
insertionResult.setInsertionError(FeedInsertionResult.FeedInsertionError.PARSE_ERROR);
insertionResult.setInsertionError(FeedInsertionResult.FeedInsertionError.UNKNOWN_ERROR);
} finally {
insertionResult.setParsingResult(parsingResult);
insertionResults.add(insertionResult);
}
@ -152,67 +129,38 @@ public class LocalFeedRepository extends ARepository<Void> {
});
}
private void insertNewItems(AFeed feed, RSSQuery.RSSType type) throws ParseException {
Feed dbFeed;
List<Item> items;
@SuppressWarnings("SimplifyStreamApiCallChains")
private void insertNewItems(Feed feed, 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);
int maxItems = Integer.parseInt(SharedPreferencesManager.readString(context, SharedPreferencesManager.SharedPrefKey.ITEMS_TO_PARSE_MAX_NB));
if (maxItems > 0 && items.size() > maxItems)
int maxItems = Integer.parseInt(SharedPreferencesManager.readString(context,
SharedPreferencesManager.SharedPrefKey.ITEMS_TO_PARSE_MAX_NB));
if (maxItems > 0 && items.size() > maxItems) {
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
}
setFeedColors(dbFeed);
dbFeed.setAccountId(account.getId());
setFeedColors(feed);
feed.setAccountId(account.getId());
// we need empty headers to query the feed just after, without any 304 result
dbFeed.setEtag(null);
dbFeed.setLastModified(null);
feed.setEtag(null);
feed.setLastModified(null);
dbFeed.setId((int) (database.feedDao().compatInsert(dbFeed)));
return dbFeed;
feed.setId((int) (database.feedDao().compatInsert(feed)));
return feed;
}
private void insertItems(Collection<Item> items, Feed feed) {
@ -253,13 +201,4 @@ public class LocalFeedRepository extends ARepository<Void> {
syncResult.getItems().addAll(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")
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")
public abstract boolean feedExists(String feedUrl, int accountId);