Add Fever initial and classic synchronisation logic

This commit is contained in:
Shinokuni 2021-12-28 20:09:15 +01:00
parent fe57d5b2d7
commit dcf58a537e
5 changed files with 74 additions and 19 deletions

View File

@ -1,7 +1,9 @@
package com.readrops.api.services.fever package com.readrops.api.services.fever
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 okhttp3.MultipartBody import okhttp3.MultipartBody
@ -11,28 +13,70 @@ class FeverDataSource(private val service: FeverService) {
val credentials = ApiUtils.md5hash("$login:$password") val credentials = ApiUtils.md5hash("$login:$password")
val requestBody = MultipartBody.Builder() val requestBody = MultipartBody.Builder()
.setType(MultipartBody.FORM) .setType(MultipartBody.FORM)
.addFormDataPart("api_key", credentials) .addFormDataPart("api_key", credentials)
.build() .build()
val response = service.login(requestBody) val response = service.login(requestBody)
val adapter = Moshi.Builder() val adapter = Moshi.Builder()
.add(Boolean::class.java, FeverAPIAdapter()) .add(Boolean::class.java, FeverAPIAdapter())
.build() .build()
.adapter(Boolean::class.java) .adapter(Boolean::class.java)
adapter.fromJson(response.source())!! adapter.fromJson(response.source())!!
} }
suspend fun sync(body: MultipartBody): FeverSyncResult { suspend fun sync(syncType: SyncType, syncData: FeverSyncData, body: MultipartBody): FeverSyncResult {
return FeverSyncResult( if (syncType == SyncType.INITIAL_SYNC) {
feverFeeds = service.getFeeds(body), val unreadIds = service.getUnreadItemsIds(body)
folders = service.getFolders(body), .reversed()
items = service.getItems(body), .subList(0, MAX_ITEMS_IDS)
unreadIds = service.getUnreadItemsIds(body),
starredIds = service.getStarredItemsIds(body), var lastId = unreadIds.first()
favicons = listOf(), val items = arrayListOf<Item>()
) repeat(INITIAL_SYNC_ITEMS_REQUESTS_COUNT) {
val newItems = service.getItems(body, lastId, null)
lastId = newItems.last().remoteId!!
items += newItems
}
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 {
val items = arrayListOf<Item>()
var sinceId = syncData.sinceId
while (true) {
val newItems = service.getItems(body, null, sinceId)
if (newItems.isEmpty()) break
sinceId = newItems.first().remoteId!!
items += newItems
}
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(),
)
}
}
companion object {
private const val MAX_ITEMS_IDS = 5000
private const val INITIAL_SYNC_ITEMS_REQUESTS_COUNT = 10
} }
} }

View File

@ -2,14 +2,13 @@ package com.readrops.api.services.fever
import com.readrops.api.services.fever.adapters.Favicon import com.readrops.api.services.fever.adapters.Favicon
import com.readrops.api.services.fever.adapters.FeverFeeds import com.readrops.api.services.fever.adapters.FeverFeeds
import com.readrops.db.entities.Feed
import com.readrops.db.entities.Folder import com.readrops.db.entities.Folder
import com.readrops.db.entities.Item import com.readrops.db.entities.Item
import okhttp3.MultipartBody import okhttp3.MultipartBody
import okhttp3.ResponseBody import okhttp3.ResponseBody
import retrofit2.http.Body import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.POST import retrofit2.http.POST
import retrofit2.http.Query
interface FeverService { interface FeverService {
@ -26,7 +25,8 @@ interface FeverService {
suspend fun getFavicons(@Body body: MultipartBody): List<Favicon> suspend fun getFavicons(@Body body: MultipartBody): List<Favicon>
@POST("?items") @POST("?items")
suspend fun getItems(@Body body: MultipartBody): List<Item> suspend fun getItems(@Body body: MultipartBody, @Query("max_id") maxId: String?,
@Query("since_id") sinceId: String?): List<Item>
@POST("?unread_item_ids") @POST("?unread_item_ids")
suspend fun getUnreadItemsIds(@Body body: MultipartBody): List<String> suspend fun getUnreadItemsIds(@Body body: MultipartBody): List<String>

View File

@ -0,0 +1,5 @@
package com.readrops.api.services.fever
data class FeverSyncData(
val sinceId: String,
)

View File

@ -12,4 +12,5 @@ data class FeverSyncResult(
val unreadIds: List<String>, val unreadIds: List<String>,
val starredIds: List<String>, val starredIds: List<String>,
val favicons: List<Favicon>, val favicons: List<Favicon>,
val sinceId: Long = 0,
) )

View File

@ -4,6 +4,7 @@ import android.content.Context
import android.util.Log import android.util.Log
import com.readrops.api.services.SyncType import com.readrops.api.services.SyncType
import com.readrops.api.services.fever.FeverDataSource import com.readrops.api.services.fever.FeverDataSource
import com.readrops.api.services.fever.FeverSyncData
import com.readrops.api.services.fever.adapters.FeverFeeds import com.readrops.api.services.fever.adapters.FeverFeeds
import com.readrops.api.utils.ApiUtils import com.readrops.api.utils.ApiUtils
import com.readrops.app.addfeed.FeedInsertionResult import com.readrops.app.addfeed.FeedInsertionResult
@ -62,13 +63,17 @@ class FeverRepository(
.addFormDataPart("api_key", credentials) .addFormDataPart("api_key", credentials)
.build() .build()
val syncResult = feverDataSource.sync(requestBody) val syncResult = feverDataSource.sync(syncType,
FeverSyncData(account.lastModified.toString()), requestBody)
insertFolders(syncResult.folders) insertFolders(syncResult.folders)
insertFeeds(syncResult.feverFeeds) insertFeeds(syncResult.feverFeeds)
insertItems(syncResult.items) insertItems(syncResult.items)
insertItemsIds(syncResult.unreadIds, syncResult.starredIds.toMutableList()) insertItemsIds(syncResult.unreadIds, syncResult.starredIds.toMutableList())
// We store the id to use for the next synchronisation even if it's not a timestamp
database.accountDao().updateLastModified(account.id, syncResult.sinceId)
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "sync: ${e.message}") Log.e(TAG, "sync: ${e.message}")
error(e.message!!) error(e.message!!)