mirror of https://github.com/readrops/Readrops.git
Rework Fever synchronization to be more efficient
This commit is contained in:
parent
732ae4efa4
commit
89c4dfad1a
|
@ -3,8 +3,11 @@ package com.readrops.api.services.fever
|
||||||
import com.readrops.api.services.SyncType
|
import com.readrops.api.services.SyncType
|
||||||
import com.readrops.api.services.fever.adapters.FeverAPIAdapter
|
import com.readrops.api.services.fever.adapters.FeverAPIAdapter
|
||||||
import com.readrops.api.utils.ApiUtils
|
import com.readrops.api.utils.ApiUtils
|
||||||
import com.readrops.db.entities.Item
|
|
||||||
import com.squareup.moshi.Moshi
|
import com.squareup.moshi.Moshi
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.async
|
||||||
|
import kotlinx.coroutines.awaitAll
|
||||||
import okhttp3.MultipartBody
|
import okhttp3.MultipartBody
|
||||||
|
|
||||||
class FeverDataSource(private val service: FeverService) {
|
class FeverDataSource(private val service: FeverService) {
|
||||||
|
@ -21,54 +24,68 @@ class FeverDataSource(private val service: FeverService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun synchronize(
|
suspend fun synchronize(
|
||||||
|
login: String,
|
||||||
|
password: String,
|
||||||
syncType: SyncType,
|
syncType: SyncType,
|
||||||
syncData: FeverSyncData,
|
syncData: FeverSyncData
|
||||||
body: MultipartBody
|
): FeverSyncResult = with(CoroutineScope(Dispatchers.IO)) {
|
||||||
): FeverSyncResult {
|
val body = getFeverRequestBody(login, password)
|
||||||
|
|
||||||
if (syncType == SyncType.INITIAL_SYNC) {
|
if (syncType == SyncType.INITIAL_SYNC) {
|
||||||
val unreadIds = service.getUnreadItemsIds(body)
|
return FeverSyncResult().apply {
|
||||||
.reversed()
|
listOf(
|
||||||
.subList(0, MAX_ITEMS_IDS)
|
async { feverFeeds = service.getFeeds(body) },
|
||||||
|
async { folders = service.getFolders(body) },
|
||||||
|
async {
|
||||||
|
unreadIds = service.getUnreadItemsIds(body)
|
||||||
|
.reversed()
|
||||||
|
.subList(0, MAX_ITEMS_IDS)
|
||||||
|
|
||||||
var lastId = unreadIds.first()
|
var lastId = unreadIds.first()
|
||||||
val items = arrayListOf<Item>()
|
items = buildList {
|
||||||
repeat(INITIAL_SYNC_ITEMS_REQUESTS_COUNT) {
|
repeat(INITIAL_SYNC_ITEMS_REQUESTS_COUNT) {
|
||||||
val newItems = service.getItems(body, lastId, null)
|
val newItems = service.getItems(body, lastId, null)
|
||||||
|
|
||||||
lastId = newItems.last().remoteId!!
|
lastId = newItems.last().remoteId!!
|
||||||
items += newItems
|
addAll(newItems)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sinceId = unreadIds.first().toLong()
|
||||||
|
},
|
||||||
|
async { starredIds = service.getStarredItemsIds(body) },
|
||||||
|
async { favicons = listOf() }
|
||||||
|
)
|
||||||
|
.awaitAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
return FeverSyncResult(
|
|
||||||
feverFeeds = service.getFeeds(body),
|
|
||||||
folders = service.getFolders(body),
|
|
||||||
items = items,
|
|
||||||
unreadIds = unreadIds,
|
|
||||||
starredIds = service.getStarredItemsIds(body),
|
|
||||||
favicons = listOf(),
|
|
||||||
sinceId = unreadIds.first().toLong(),
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
val items = arrayListOf<Item>()
|
return FeverSyncResult().apply {
|
||||||
var sinceId = syncData.sinceId
|
listOf(
|
||||||
|
async { folders = service.getFolders(body) },
|
||||||
|
async { feverFeeds = service.getFeeds(body) },
|
||||||
|
async { unreadIds = service.getUnreadItemsIds(body) },
|
||||||
|
async { starredIds = service.getStarredItemsIds(body) },
|
||||||
|
async { favicons = listOf() },
|
||||||
|
async {
|
||||||
|
items = buildList {
|
||||||
|
var sinceId = syncData.sinceId
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
val newItems = service.getItems(body, null, sinceId)
|
val newItems = service.getItems(body, null, sinceId)
|
||||||
|
|
||||||
if (newItems.isEmpty()) break
|
if (newItems.isEmpty()) break
|
||||||
sinceId = newItems.first().remoteId!!
|
sinceId = newItems.first().remoteId!!
|
||||||
items += newItems
|
addAll(newItems)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (items.isNotEmpty()) items.first().remoteId!!.toLong() else sinceId.toLong()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.awaitAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
return FeverSyncResult(
|
|
||||||
feverFeeds = service.getFeeds(body),
|
|
||||||
folders = service.getFolders(body),
|
|
||||||
items = items,
|
|
||||||
unreadIds = service.getUnreadItemsIds(body),
|
|
||||||
starredIds = service.getStarredItemsIds(body),
|
|
||||||
favicons = listOf(),
|
|
||||||
sinceId = if (items.isNotEmpty()) items.first().remoteId!!.toLong() else sinceId.toLong(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,11 +6,11 @@ import com.readrops.db.entities.Folder
|
||||||
import com.readrops.db.entities.Item
|
import com.readrops.db.entities.Item
|
||||||
|
|
||||||
data class FeverSyncResult(
|
data class FeverSyncResult(
|
||||||
val feverFeeds: FeverFeeds,
|
var feverFeeds: FeverFeeds = FeverFeeds(),
|
||||||
val folders: List<Folder>,
|
var folders: List<Folder> = listOf(),
|
||||||
val items: List<Item>,
|
var items: List<Item> = listOf(),
|
||||||
val unreadIds: List<String>,
|
var unreadIds: List<String> = listOf(),
|
||||||
val starredIds: List<String>,
|
var starredIds: List<String> = listOf(),
|
||||||
val favicons: List<Favicon>,
|
var favicons: List<Favicon> = listOf(),
|
||||||
val sinceId: Long = 0,
|
var sinceId: Long = 0,
|
||||||
)
|
)
|
|
@ -5,13 +5,14 @@ import com.readrops.api.utils.exceptions.ParseException
|
||||||
import com.readrops.api.utils.extensions.nextNonEmptyString
|
import com.readrops.api.utils.extensions.nextNonEmptyString
|
||||||
import com.readrops.api.utils.extensions.nextNullableString
|
import com.readrops.api.utils.extensions.nextNullableString
|
||||||
import com.readrops.api.utils.extensions.skipField
|
import com.readrops.api.utils.extensions.skipField
|
||||||
import com.readrops.api.utils.extensions.skipToEnd
|
|
||||||
import com.readrops.db.entities.Feed
|
import com.readrops.db.entities.Feed
|
||||||
import com.squareup.moshi.*
|
import com.squareup.moshi.JsonAdapter
|
||||||
|
import com.squareup.moshi.JsonReader
|
||||||
|
import com.squareup.moshi.JsonWriter
|
||||||
|
|
||||||
data class FeverFeeds(
|
data class FeverFeeds(
|
||||||
val feeds: List<Feed>,
|
val feeds: List<Feed> = listOf(),
|
||||||
val feedsGroups: Map<Int, List<Int>>
|
val feedsGroups: Map<Int, List<Int>> = emptyMap()
|
||||||
)
|
)
|
||||||
|
|
||||||
class FeverFeedsAdapter : JsonAdapter<FeverFeeds>() {
|
class FeverFeedsAdapter : JsonAdapter<FeverFeeds>() {
|
||||||
|
|
|
@ -41,20 +41,24 @@ class FeverRepository(
|
||||||
}
|
}
|
||||||
|
|
||||||
return feverDataSource.synchronize(
|
return feverDataSource.synchronize(
|
||||||
|
account.login!!,
|
||||||
|
account.password!!,
|
||||||
syncType,
|
syncType,
|
||||||
FeverSyncData(account.lastModified.toString()),
|
FeverSyncData(account.lastModified.toString())
|
||||||
getFeverRequestBody()
|
|
||||||
).run {
|
).run {
|
||||||
insertFolders(folders)
|
insertFolders(folders)
|
||||||
insertFeeds(feverFeeds)
|
val newFeeds = insertFeeds(feverFeeds)
|
||||||
|
|
||||||
insertItems(items)
|
val newItems = insertItems(items)
|
||||||
insertItemsIds(unreadIds, starredIds.toMutableList())
|
insertItemsIds(unreadIds, starredIds.toMutableList())
|
||||||
|
|
||||||
// We store the id to use for the next synchronisation even if it's not a timestamp
|
// We store the id to use for the next synchronisation even if it's not a timestamp
|
||||||
database.accountDao().updateLastModified(sinceId, account.id)
|
database.accountDao().updateLastModified(sinceId, account.id)
|
||||||
|
|
||||||
SyncResult()
|
SyncResult(
|
||||||
|
items = newItems,
|
||||||
|
feeds = newFeeds
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,7 +148,7 @@ class FeverRepository(
|
||||||
database.folderDao().upsertFolders(folders, account)
|
database.folderDao().upsertFolders(folders, account)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun insertFeeds(feverFeeds: FeverFeeds) = with(feverFeeds) {
|
private suspend fun insertFeeds(feverFeeds: FeverFeeds): List<Feed> = with(feverFeeds) {
|
||||||
for (feed in feeds) {
|
for (feed in feeds) {
|
||||||
for ((folderId, feedsIds) in feedsGroups) {
|
for ((folderId, feedsIds) in feedsGroups) {
|
||||||
if (feedsIds.contains(feed.remoteId!!.toInt())) {
|
if (feedsIds.contains(feed.remoteId!!.toInt())) {
|
||||||
|
@ -154,23 +158,23 @@ class FeverRepository(
|
||||||
}
|
}
|
||||||
|
|
||||||
feeds.forEach { it.accountId = account.id }
|
feeds.forEach { it.accountId = account.id }
|
||||||
database.feedDao().upsertFeeds(feeds, account)
|
return database.feedDao().upsertFeeds(feeds, account)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun insertItems(items: List<Item>): List<Item> {
|
private suspend fun insertItems(items: List<Item>): List<Item> {
|
||||||
val newItems = arrayListOf<Item>()
|
val newItems = arrayListOf<Item>()
|
||||||
val itemsFeedsIds = mutableMapOf<String, Int>()
|
val itemsFeedsIds = mutableMapOf<String?, Int>()
|
||||||
|
|
||||||
for (item in items) {
|
for (item in items) {
|
||||||
var feedId: Int?
|
val feedId: Int
|
||||||
if (itemsFeedsIds.containsKey(item.feedRemoteId)) {
|
if (itemsFeedsIds.containsKey(item.feedRemoteId)) {
|
||||||
feedId = itemsFeedsIds[item.feedRemoteId]
|
feedId = itemsFeedsIds.getValue(item.feedRemoteId)
|
||||||
} else {
|
} else {
|
||||||
//feedId = database.feedDao().getFeedIdByRemoteId(item.feedRemoteId!!, account.id)
|
feedId = database.feedDao().selectRemoteFeedLocalId(item.feedRemoteId!!, account.id)
|
||||||
// itemsFeedsIds[item.feedRemoteId!!] = feedId
|
itemsFeedsIds[item.feedRemoteId!!] = feedId
|
||||||
}
|
}
|
||||||
|
|
||||||
//item.feedId = feedId!!
|
item.feedId = feedId
|
||||||
item.text?.let { item.readTime = Utils.readTimeFromString(it) }
|
item.text?.let { item.readTime = Utils.readTimeFromString(it) }
|
||||||
|
|
||||||
newItems += item
|
newItems += item
|
||||||
|
|
Loading…
Reference in New Issue