Crash fixes (#337)

* Add diffing logs and be more aggresive about unexpected states
* Move diff collection on a serial queue
* Handle now optional `addTimelineListener` result
* Treat RoomSummaryProvider invalidations separately
* Bump RustSDK to v0.0.9-demo
This commit is contained in:
Stefan Ceriu
2022-11-24 15:32:23 +02:00
committed by GitHub
parent 83410aa660
commit 7d8e94d3a7
9 changed files with 149 additions and 62 deletions
@@ -57,7 +57,9 @@ struct MockRoomProxy: RoomProxyProtocol {
func startLiveEventListener() { }
func addTimelineListener(listener: TimelineListener) { }
func addTimelineListener(listener: TimelineListener) -> Result<Void, RoomProxyError> {
.failure(.failedAddingTimelineListener)
}
func paginateBackwards(count: UInt) async -> Result<Void, RoomProxyError> {
.failure(.failedPaginatingBackwards)
@@ -141,8 +141,12 @@ class RoomProxy: RoomProxyProtocol {
}
}
func addTimelineListener(listener: TimelineListener) {
slidingSyncRoom.addTimelineListener(listener: listener)
func addTimelineListener(listener: TimelineListener) -> Result<Void, RoomProxyError> {
if let result = slidingSyncRoom.addTimelineListener(listener: listener), result == true {
return .success(())
} else {
return .failure(.failedAddingTimelineListener)
}
}
func paginateBackwards(count: UInt) async -> Result<Void, RoomProxyError> {
@@ -26,6 +26,7 @@ enum RoomProxyError: Error {
case failedRetrievingMemberDisplayName
case failedSendingMessage
case failedRedactingEvent
case failedAddingTimelineListener
}
@MainActor
@@ -54,7 +55,7 @@ protocol RoomProxyProtocol {
func loadDisplayName() async -> Result<String, RoomProxyError>
func addTimelineListener(listener: TimelineListener)
func addTimelineListener(listener: TimelineListener) -> Result<Void, RoomProxyError>
func paginateBackwards(count: UInt) async -> Result<Void, RoomProxyError>
@@ -31,18 +31,21 @@ private class WeakRoomSummaryProviderWrapper: SlidingSyncViewRoomListObserver, S
// MARK: - SlidingSyncViewRoomListObserver
func didReceiveUpdate(diff: SlidingSyncViewRoomsListDiff) {
MXLog.verbose("Received room diff")
roomListDiffPublisher.send(diff)
}
// MARK: - SlidingSyncViewStateObserver
func didReceiveUpdate(newState: SlidingSyncState) {
MXLog.verbose("Updated state: \(newState)")
stateUpdatePublisher.send(newState)
}
// MARK: - SlidingSyncViewRoomsCountObserver
func didReceiveUpdate(count: UInt32) {
MXLog.verbose("Updated room count: \(count)")
countUpdatePublisher.send(UInt(count))
}
}
@@ -51,6 +54,7 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol {
private let slidingSyncController: SlidingSyncProtocol
private let slidingSyncView: SlidingSyncViewProtocol
private let roomMessageFactory: RoomMessageFactoryProtocol
private let serialDispatchQueue: DispatchQueue
private var listUpdateObserverToken: StoppableSpawn?
private var stateUpdateObserverToken: StoppableSpawn?
@@ -78,6 +82,7 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol {
self.slidingSyncView = slidingSyncView
self.slidingSyncController = slidingSyncController
self.roomMessageFactory = roomMessageFactory
serialDispatchQueue = DispatchQueue(label: "io.element.elementx.roomsummaryprovider")
let weakProvider = WeakRoomSummaryProviderWrapper()
@@ -97,7 +102,7 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol {
.store(in: &cancellables)
weakProvider.roomListDiffPublisher
.collect(.byTime(DispatchQueue.global(), 0.25))
.collect(.byTime(serialDispatchQueue, 0.25))
.sink { self.updateRoomsWithDiffs($0) }
.store(in: &cancellables)
@@ -140,14 +145,31 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol {
// MARK: - Private
fileprivate func updateRoomsWithDiffs(_ diffs: [SlidingSyncViewRoomsListDiff]) {
MXLog.verbose("Received diffs")
rooms = diffs
.reduce(rooms) { partialResult, diff in
guard let collectionDiff = buildDiff(from: diff, on: partialResult) else {
return partialResult
.reduce(rooms) { currentItems, diff in
// Invalidations are a no-op for the moment
if diff.isInvalidation {
return currentItems
}
return partialResult.applying(collectionDiff) ?? partialResult
guard let collectionDiff = buildDiff(from: diff, on: currentItems) else {
MXLog.error("Failed building CollectionDifference from \(diff)")
return currentItems
}
guard let updatedItems = currentItems.applying(collectionDiff) else {
MXLog.error("Failed applying diff: \(collectionDiff)")
return currentItems
}
MXLog.verbose("Applied diff \(collectionDiff), new count: \(updatedItems.count)")
return updatedItems
}
MXLog.verbose("Finished applying diffs")
}
private func buildEmptyRoomSummary(forIdentifier identifier: String = UUID().uuidString) -> RoomSummary {
@@ -192,32 +214,33 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol {
}
private func buildDiff(from diff: SlidingSyncViewRoomsListDiff, on rooms: [RoomSummary]) -> CollectionDifference<RoomSummary>? {
// Invalidations are a no-op for the moment
if diff.isInvalidation {
return nil
}
var changes = [CollectionDifference<RoomSummary>.Change]()
switch diff {
case .push(value: let value):
MXLog.verbose("Push")
let summary = buildSummaryForRoomListEntry(value)
changes.append(.insert(offset: Int(rooms.count), element: summary, associatedWith: nil))
case .updateAt(let index, let value):
MXLog.verbose("Update \(index), current total count: \(rooms.count)")
let summary = buildSummaryForRoomListEntry(value)
changes.append(.remove(offset: Int(index), element: summary, associatedWith: nil))
changes.append(.insert(offset: Int(index), element: summary, associatedWith: nil))
case .insertAt(let index, let value):
MXLog.verbose("Insert at \(index), current total count: \(rooms.count)")
let summary = buildSummaryForRoomListEntry(value)
changes.append(.insert(offset: Int(index), element: summary, associatedWith: nil))
case .move(let oldIndex, let newIndex):
MXLog.verbose("Move from: \(oldIndex) to: \(newIndex), current total count: \(rooms.count)")
let summary = rooms[Int(oldIndex)]
changes.append(.remove(offset: Int(oldIndex), element: summary, associatedWith: nil))
changes.append(.insert(offset: Int(newIndex), element: summary, associatedWith: nil))
case .removeAt(let index):
MXLog.verbose("Remove from: \(index), current total count: \(rooms.count)")
let summary = rooms[Int(index)]
changes.append(.remove(offset: Int(index), element: summary, associatedWith: nil))
case .replace(let values):
MXLog.verbose("Replace all items with new count: \(values.count), current total count: \(rooms.count)")
for (index, summary) in rooms.enumerated() {
changes.append(.remove(offset: index, element: summary, associatedWith: nil))
}