Prevent race conditions when adding timeline listeners between the timeline provider and other screens

This commit is contained in:
Stefan Ceriu
2023-05-26 17:34:20 +03:00
committed by Stefan Ceriu
parent 0082aba9d4
commit 142a8d6275
4 changed files with 24 additions and 23 deletions
@@ -186,13 +186,14 @@ class RoomProxy: RoomProxyProtocol {
timelineLimit: UInt32(SlidingSyncConstants.timelinePrecachingTimelineLimit)) timelineLimit: UInt32(SlidingSyncConstants.timelinePrecachingTimelineLimit))
roomSubscriptionObservationToken = slidingSyncRoom.subscribeToRoom(settings: settings) roomSubscriptionObservationToken = slidingSyncRoom.subscribeToRoom(settings: settings)
let listener = RoomTimelineListener { [weak self] timelineDiff in let timelineListener = RoomTimelineListener { [weak self] timelineDiff in
self?.updatesSubject.send(timelineDiff) self?.updatesSubject.send(timelineDiff)
} }
if let result = try? slidingSyncRoom.addTimelineListener(listener: listener) { self.timelineListener = timelineListener
if let result = try? slidingSyncRoom.addTimelineListener(listener: timelineListener) {
roomTimelineObservationToken = result.taskHandle roomTimelineObservationToken = result.taskHandle
timelineListener = listener
Task { Task {
await fetchMembers() await fetchMembers()
@@ -200,6 +201,7 @@ class RoomProxy: RoomProxyProtocol {
} }
return .success(result.items) return .success(result.items)
} else { } else {
self.timelineListener = nil
return .failure(.failedAddingTimelineListener) return .failure(.failedAddingTimelineListener)
} }
} }
@@ -39,24 +39,22 @@ class RoomTimelineProvider: RoomTimelineProviderProtocol {
self.roomProxy = roomProxy self.roomProxy = roomProxy
serialDispatchQueue = DispatchQueue(label: "io.element.elementx.roomtimelineprovider", qos: .utility) serialDispatchQueue = DispatchQueue(label: "io.element.elementx.roomtimelineprovider", qos: .utility)
itemProxies = [] itemProxies = []
Task { @MainActor in roomProxy
roomProxy .updatesPublisher
.updatesPublisher .collect(.byTime(serialDispatchQueue, 0.1))
.collect(.byTime(serialDispatchQueue, 0.1)) .sink { [weak self] in self?.updateItemsWithDiffs($0) }
.sink { [weak self] in self?.updateItemsWithDiffs($0) } .store(in: &cancellables)
.store(in: &cancellables)
switch roomProxy.registerTimelineListenerIfNeeded() {
switch roomProxy.registerTimelineListenerIfNeeded() { case let .success(items):
case let .success(items): itemProxies = items.map(TimelineItemProxy.init)
itemProxies = items.map(TimelineItemProxy.init) MXLog.info("Added timeline listener, current items (\(items.count)) : \(items.map(\.debugIdentifier))")
MXLog.info("Added timeline listener, current items (\(items.count)) : \(items.map(\.debugIdentifier))") case .failure(.roomListenerAlreadyRegistered):
case .failure(.roomListenerAlreadyRegistered): MXLog.info("Listener already registered for the room: \(roomProxy.id)")
MXLog.info("Listener already registered for the room: \(roomProxy.id)") case .failure:
case .failure: let roomID = roomProxy.id
let roomID = roomProxy.id MXLog.error("Failed adding timeline listener on room with identifier: \(roomID)")
MXLog.error("Failed adding timeline listener on room with identifier: \(roomID)")
}
} }
} }
@@ -17,6 +17,7 @@
import Combine import Combine
import Foundation import Foundation
@MainActor
protocol RoomTimelineProviderProtocol { protocol RoomTimelineProviderProtocol {
var itemsPublisher: CurrentValuePublisher<[TimelineItemProxy], Never> { get } var itemsPublisher: CurrentValuePublisher<[TimelineItemProxy], Never> { get }
} }
@@ -491,7 +491,7 @@ class MockScreen: Identifiable {
let mockUserSession = MockUserSession(clientProxy: clientProxy, mediaProvider: MockMediaProvider()) let mockUserSession = MockUserSession(clientProxy: clientProxy, mediaProvider: MockMediaProvider())
let createRoomParameters = CreateRoomFlowParameters() let createRoomParameters = CreateRoomFlowParameters()
let selectedUsers: [UserProfile] = [.mockAlice, .mockBob, .mockCharlie] let selectedUsers: [UserProfile] = [.mockAlice, .mockBob, .mockCharlie]
let parameters = CreateRoomCoordinatorParameters(userSession: mockUserSession, userIndicatorController: MockUserIndicatorController(), createRoomParameters: .init(createRoomParameters), selectedUsers: .init(selectedUsers)) let parameters = CreateRoomCoordinatorParameters(userSession: mockUserSession, userIndicatorController: nil, createRoomParameters: .init(createRoomParameters), selectedUsers: .init(selectedUsers))
let coordinator = CreateRoomCoordinator(parameters: parameters) let coordinator = CreateRoomCoordinator(parameters: parameters)
navigationStackCoordinator.setRootCoordinator(coordinator) navigationStackCoordinator.setRootCoordinator(coordinator)
return navigationStackCoordinator return navigationStackCoordinator
@@ -500,7 +500,7 @@ class MockScreen: Identifiable {
let clientProxy = MockClientProxy(userID: "@mock:client.com") let clientProxy = MockClientProxy(userID: "@mock:client.com")
let mockUserSession = MockUserSession(clientProxy: clientProxy, mediaProvider: MockMediaProvider()) let mockUserSession = MockUserSession(clientProxy: clientProxy, mediaProvider: MockMediaProvider())
let createRoomParameters = CreateRoomFlowParameters() let createRoomParameters = CreateRoomFlowParameters()
let parameters = CreateRoomCoordinatorParameters(userSession: mockUserSession, userIndicatorController: MockUserIndicatorController(), createRoomParameters: .init(createRoomParameters), selectedUsers: .init([])) let parameters = CreateRoomCoordinatorParameters(userSession: mockUserSession, userIndicatorController: nil, createRoomParameters: .init(createRoomParameters), selectedUsers: .init([]))
let coordinator = CreateRoomCoordinator(parameters: parameters) let coordinator = CreateRoomCoordinator(parameters: parameters)
navigationStackCoordinator.setRootCoordinator(coordinator) navigationStackCoordinator.setRootCoordinator(coordinator)
return navigationStackCoordinator return navigationStackCoordinator