mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-26 19:36:08 +03:00
Timeline: fetch next token with the help of getContext when required
This commit is contained in:
parent
ffeae7ec83
commit
458e3ee5e8
5 changed files with 138 additions and 55 deletions
|
@ -56,8 +56,10 @@ import im.vector.matrix.android.internal.session.room.reporting.DefaultReportCon
|
|||
import im.vector.matrix.android.internal.session.room.reporting.ReportContentTask
|
||||
import im.vector.matrix.android.internal.session.room.state.DefaultSendStateTask
|
||||
import im.vector.matrix.android.internal.session.room.state.SendStateTask
|
||||
import im.vector.matrix.android.internal.session.room.timeline.DefaultFetchNextTokenAndPaginateTask
|
||||
import im.vector.matrix.android.internal.session.room.timeline.DefaultGetContextOfEventTask
|
||||
import im.vector.matrix.android.internal.session.room.timeline.DefaultPaginationTask
|
||||
import im.vector.matrix.android.internal.session.room.timeline.FetchNextTokenAndPaginateTask
|
||||
import im.vector.matrix.android.internal.session.room.timeline.GetContextOfEventTask
|
||||
import im.vector.matrix.android.internal.session.room.timeline.PaginationTask
|
||||
import im.vector.matrix.android.internal.session.room.typing.DefaultSendTypingTask
|
||||
|
@ -143,6 +145,9 @@ internal abstract class RoomModule {
|
|||
@Binds
|
||||
abstract fun bindPaginationTask(task: DefaultPaginationTask): PaginationTask
|
||||
|
||||
@Binds
|
||||
abstract fun bindFetchNextTokenAndPaginateTask(task: DefaultFetchNextTokenAndPaginateTask): FetchNextTokenAndPaginateTask
|
||||
|
||||
@Binds
|
||||
abstract fun bindFetchEditHistoryTask(task: DefaultFetchEditHistoryTask): FetchEditHistoryTask
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package im.vector.matrix.android.internal.session.room.timeline
|
||||
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.extensions.orFalse
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.api.session.events.model.RelationType
|
||||
import im.vector.matrix.android.api.session.events.model.toModel
|
||||
|
@ -71,6 +72,7 @@ internal class DefaultTimeline(
|
|||
private val realmConfiguration: RealmConfiguration,
|
||||
private val taskExecutor: TaskExecutor,
|
||||
private val contextOfEventTask: GetContextOfEventTask,
|
||||
private val fetchNextTokenAndPaginateTask: FetchNextTokenAndPaginateTask,
|
||||
private val paginationTask: PaginationTask,
|
||||
private val timelineEventMapper: TimelineEventMapper,
|
||||
private val settings: TimelineSettings,
|
||||
|
@ -519,51 +521,45 @@ internal class DefaultTimeline(
|
|||
* This has to be called on TimelineThread as it accesses realm live results
|
||||
*/
|
||||
private fun executePaginationTask(direction: Timeline.Direction, limit: Int) {
|
||||
val token = getTokenLive(direction)
|
||||
if (token == null) {
|
||||
val currentChunk = getLiveChunk()
|
||||
if (direction == Timeline.Direction.FORWARDS && currentChunk?.hasBeenALastForwardChunk() == true) {
|
||||
val token = if (direction == Timeline.Direction.BACKWARDS) currentChunk?.prevToken else currentChunk?.nextToken
|
||||
if (token == null) {
|
||||
if (direction == Timeline.Direction.FORWARDS && currentChunk?.hasBeenALastForwardChunk().orFalse()) {
|
||||
// We are in the case that next event exists, but we do not know the next token.
|
||||
// Fetch (again) the last event to get a nextToken
|
||||
currentChunk.timelineEvents.lastOrNull()?.eventId?.let { fetchEvent(it) }
|
||||
}
|
||||
val lastKnownEventId = nonFilteredEvents.firstOrNull()?.eventId
|
||||
if (lastKnownEventId == null) {
|
||||
updateState(direction) { it.copy(isPaginating = false, requestedPaginationCount = 0) }
|
||||
return
|
||||
} else {
|
||||
val params = FetchNextTokenAndPaginateTask.Params(
|
||||
roomId = roomId,
|
||||
limit = limit,
|
||||
lastKnownEventId = lastKnownEventId
|
||||
)
|
||||
cancelableBag += fetchNextTokenAndPaginateTask
|
||||
.configureWith(params) {
|
||||
this.callback = createPaginationCallback(limit, direction)
|
||||
}
|
||||
val params = PaginationTask.Params(roomId = roomId,
|
||||
.executeBy(taskExecutor)
|
||||
}
|
||||
} else {
|
||||
updateState(direction) { it.copy(isPaginating = false, requestedPaginationCount = 0) }
|
||||
}
|
||||
} else {
|
||||
val params = PaginationTask.Params(
|
||||
roomId = roomId,
|
||||
from = token,
|
||||
direction = direction.toPaginationDirection(),
|
||||
limit = limit)
|
||||
|
||||
limit = limit
|
||||
)
|
||||
Timber.v("Should fetch $limit items $direction")
|
||||
cancelableBag += paginationTask
|
||||
.configureWith(params) {
|
||||
this.callback = object : MatrixCallback<TokenChunkEventPersistor.Result> {
|
||||
override fun onSuccess(data: TokenChunkEventPersistor.Result) {
|
||||
when (data) {
|
||||
TokenChunkEventPersistor.Result.SUCCESS -> {
|
||||
Timber.v("Success fetching $limit items $direction from pagination request")
|
||||
}
|
||||
TokenChunkEventPersistor.Result.REACHED_END -> {
|
||||
postSnapshot()
|
||||
}
|
||||
TokenChunkEventPersistor.Result.SHOULD_FETCH_MORE ->
|
||||
// Database won't be updated, so we force pagination request
|
||||
BACKGROUND_HANDLER.post {
|
||||
executePaginationTask(direction, limit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
updateState(direction) { it.copy(isPaginating = false, requestedPaginationCount = 0) }
|
||||
postSnapshot()
|
||||
Timber.v("Failure fetching $limit items $direction from pagination request")
|
||||
}
|
||||
}
|
||||
this.callback = createPaginationCallback(limit, direction)
|
||||
}
|
||||
.executeBy(taskExecutor)
|
||||
}
|
||||
}
|
||||
|
||||
// For debug purpose only
|
||||
private fun dumpAndLogChunks() {
|
||||
|
@ -743,6 +739,32 @@ internal class DefaultTimeline(
|
|||
forwardsState.set(State())
|
||||
}
|
||||
|
||||
private fun createPaginationCallback(limit: Int, direction: Timeline.Direction): MatrixCallback<TokenChunkEventPersistor.Result> {
|
||||
return object : MatrixCallback<TokenChunkEventPersistor.Result> {
|
||||
override fun onSuccess(data: TokenChunkEventPersistor.Result) {
|
||||
when (data) {
|
||||
TokenChunkEventPersistor.Result.SUCCESS -> {
|
||||
Timber.v("Success fetching $limit items $direction from pagination request")
|
||||
}
|
||||
TokenChunkEventPersistor.Result.REACHED_END -> {
|
||||
postSnapshot()
|
||||
}
|
||||
TokenChunkEventPersistor.Result.SHOULD_FETCH_MORE ->
|
||||
// Database won't be updated, so we force pagination request
|
||||
BACKGROUND_HANDLER.post {
|
||||
executePaginationTask(direction, limit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
updateState(direction) { it.copy(isPaginating = false, requestedPaginationCount = 0) }
|
||||
postSnapshot()
|
||||
Timber.v("Failure fetching $limit items $direction from pagination request")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Extension methods ***************************************************************************
|
||||
|
||||
private fun Timeline.Direction.toPaginationDirection(): PaginationDirection {
|
||||
|
|
|
@ -42,6 +42,7 @@ internal class DefaultTimelineService @AssistedInject constructor(@Assisted priv
|
|||
private val contextOfEventTask: GetContextOfEventTask,
|
||||
private val eventDecryptor: TimelineEventDecryptor,
|
||||
private val paginationTask: PaginationTask,
|
||||
private val fetchNextTokenAndPaginateTask: FetchNextTokenAndPaginateTask,
|
||||
private val timelineEventMapper: TimelineEventMapper,
|
||||
private val readReceiptsSummaryMapper: ReadReceiptsSummaryMapper
|
||||
) : TimelineService {
|
||||
|
@ -63,7 +64,8 @@ internal class DefaultTimelineService @AssistedInject constructor(@Assisted priv
|
|||
settings = settings,
|
||||
hiddenReadReceipts = TimelineHiddenReadReceipts(readReceiptsSummaryMapper, roomId, settings),
|
||||
eventBus = eventBus,
|
||||
eventDecryptor = eventDecryptor
|
||||
eventDecryptor = eventDecryptor,
|
||||
fetchNextTokenAndPaginateTask = fetchNextTokenAndPaginateTask
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (c) 2020 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.internal.session.room.timeline
|
||||
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
||||
import im.vector.matrix.android.internal.database.query.findIncludingEvent
|
||||
import im.vector.matrix.android.internal.network.executeRequest
|
||||
import im.vector.matrix.android.internal.session.filter.FilterRepository
|
||||
import im.vector.matrix.android.internal.session.room.RoomAPI
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import im.vector.matrix.android.internal.util.awaitTransaction
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import javax.inject.Inject
|
||||
|
||||
internal interface FetchNextTokenAndPaginateTask : Task<FetchNextTokenAndPaginateTask.Params, TokenChunkEventPersistor.Result> {
|
||||
|
||||
data class Params(
|
||||
val roomId: String,
|
||||
val lastKnownEventId: String,
|
||||
val limit: Int
|
||||
)
|
||||
}
|
||||
|
||||
internal class DefaultFetchNextTokenAndPaginateTask @Inject constructor(
|
||||
private val roomAPI: RoomAPI,
|
||||
private val monarchy: Monarchy,
|
||||
private val filterRepository: FilterRepository,
|
||||
private val paginationTask: PaginationTask,
|
||||
private val eventBus: EventBus
|
||||
) : FetchNextTokenAndPaginateTask {
|
||||
|
||||
override suspend fun execute(params: FetchNextTokenAndPaginateTask.Params): TokenChunkEventPersistor.Result {
|
||||
val filter = filterRepository.getRoomFilter()
|
||||
val response = executeRequest<EventContextResponse>(eventBus) {
|
||||
apiCall = roomAPI.getContextOfEvent(params.roomId, params.lastKnownEventId, 0, filter)
|
||||
}
|
||||
if (response.end == null) {
|
||||
throw IllegalStateException("No next token found")
|
||||
}
|
||||
monarchy.awaitTransaction {
|
||||
ChunkEntity.findIncludingEvent(it, params.lastKnownEventId)?.nextToken = response.end
|
||||
}
|
||||
val paginationParams = PaginationTask.Params(
|
||||
roomId = params.roomId,
|
||||
from = response.end,
|
||||
direction = PaginationDirection.FORWARDS,
|
||||
limit = params.limit
|
||||
)
|
||||
return paginationTask.execute(paginationParams)
|
||||
}
|
||||
}
|
|
@ -230,23 +230,11 @@ internal class TokenChunkEventPersistor @Inject constructor(private val monarchy
|
|||
val chunksToDelete = ArrayList<ChunkEntity>()
|
||||
chunks.forEach {
|
||||
if (it != currentChunk) {
|
||||
if (direction == PaginationDirection.FORWARDS && it.hasBeenALastForwardChunk()) {
|
||||
// Maybe it was a trick to get a nextToken
|
||||
if (receivedChunk.events.size == 1) {
|
||||
Timber.d("Receiving a new nextToken")
|
||||
it.nextToken = receivedChunk.end
|
||||
chunksToDelete.add(currentChunk)
|
||||
} else {
|
||||
Timber.d("Do not merge $it")
|
||||
chunksToDelete.add(it)
|
||||
}
|
||||
} else {
|
||||
Timber.d("Merge $it")
|
||||
currentChunk.merge(roomId, it, direction)
|
||||
chunksToDelete.add(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
val shouldUpdateSummary = chunksToDelete.isNotEmpty() && currentChunk.isLastForward && direction == PaginationDirection.FORWARDS
|
||||
chunksToDelete.forEach {
|
||||
it.deleteOnCascade()
|
||||
|
|
Loading…
Reference in a new issue