forked from shadowfacts/Tusker
Add more logging around state restoration crash
This commit is contained in:
parent
d75c2558ca
commit
ababa4b428
|
@ -9,6 +9,7 @@
|
||||||
import UIKit
|
import UIKit
|
||||||
import Pachyderm
|
import Pachyderm
|
||||||
import Combine
|
import Combine
|
||||||
|
import Sentry
|
||||||
|
|
||||||
class TimelineViewController: UIViewController, TimelineLikeCollectionViewController, CollectionViewController, RefreshableViewController {
|
class TimelineViewController: UIViewController, TimelineLikeCollectionViewController, CollectionViewController, RefreshableViewController {
|
||||||
let timeline: Timeline
|
let timeline: Timeline
|
||||||
|
@ -335,7 +336,7 @@ class TimelineViewController: UIViewController, TimelineLikeCollectionViewContro
|
||||||
}
|
}
|
||||||
loadViewIfNeeded()
|
loadViewIfNeeded()
|
||||||
var loaded = false
|
var loaded = false
|
||||||
await controller.restoreInitial {
|
await controller.restoreInitial { @MainActor in
|
||||||
let hasStatusesToRestore = await loadStatusesToRestore(position: position)
|
let hasStatusesToRestore = await loadStatusesToRestore(position: position)
|
||||||
if hasStatusesToRestore {
|
if hasStatusesToRestore {
|
||||||
applyItemsToRestore(position: position)
|
applyItemsToRestore(position: position)
|
||||||
|
@ -351,26 +352,45 @@ class TimelineViewController: UIViewController, TimelineLikeCollectionViewContro
|
||||||
guard !unloaded.isEmpty else {
|
guard !unloaded.isEmpty else {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
let statuses = await withTaskGroup(of: Status?.self) { group -> [Status] in
|
let results = await withTaskGroup(of: (String, Result<Status, Swift.Error>).self) { group -> [(String, Result<Status, Swift.Error>)] in
|
||||||
for id in unloaded {
|
for id in unloaded {
|
||||||
group.addTask {
|
group.addTask {
|
||||||
do {
|
do {
|
||||||
let (status, _) = try await self.mastodonController.run(Client.getStatus(id: id))
|
let (status, _) = try await self.mastodonController.run(Client.getStatus(id: id))
|
||||||
return status
|
return (id, .success(status))
|
||||||
} catch {
|
} catch {
|
||||||
print(error)
|
return (id, .failure(error))
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return await group.reduce(into: []) { partialResult, status in
|
return await group.reduce(into: []) { partialResult, result in
|
||||||
if let status {
|
partialResult.append(result)
|
||||||
partialResult.append(status)
|
}
|
||||||
}
|
}
|
||||||
|
var statuses = [Status]()
|
||||||
|
for (id, result) in results {
|
||||||
|
switch result {
|
||||||
|
case .success(let status):
|
||||||
|
statuses.append(status)
|
||||||
|
case .failure(let error):
|
||||||
|
let crumb = Breadcrumb(level: .error, category: "TimelineViewController")
|
||||||
|
crumb.message = "Error loading status"
|
||||||
|
crumb.data = [
|
||||||
|
"error": String(describing: error),
|
||||||
|
"id": id
|
||||||
|
]
|
||||||
|
SentrySDK.addBreadcrumb(crumb: crumb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await mastodonController.persistentContainer.addAll(statuses: statuses, in: mastodonController.persistentContainer.viewContext)
|
await mastodonController.persistentContainer.addAll(statuses: statuses, in: mastodonController.persistentContainer.viewContext)
|
||||||
|
|
||||||
|
let crumb = Breadcrumb(level: .info, category: "TimelineViewController")
|
||||||
|
crumb.message = "Original position statusIDs"
|
||||||
|
crumb.data = [
|
||||||
|
"statusIDs": position.statusIDs,
|
||||||
|
]
|
||||||
|
SentrySDK.addBreadcrumb(crumb: crumb)
|
||||||
|
|
||||||
// update the timeline position in case some statuses couldn't be loaded
|
// update the timeline position in case some statuses couldn't be loaded
|
||||||
if let center = position.centerStatusID {
|
if let center = position.centerStatusID {
|
||||||
let nearestLoadedStatusToCenter = position.statusIDs[position.statusIDs.firstIndex(of: center)!...].first(where: { id in
|
let nearestLoadedStatusToCenter = position.statusIDs[position.statusIDs.firstIndex(of: center)!...].first(where: { id in
|
||||||
|
@ -383,9 +403,17 @@ class TimelineViewController: UIViewController, TimelineLikeCollectionViewContro
|
||||||
!unloaded.contains(id) || statuses.contains(where: { $0.id == id })
|
!unloaded.contains(id) || statuses.contains(where: { $0.id == id })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let crumb2 = Breadcrumb(level: .info, category: "TimelineViewController")
|
||||||
|
crumb2.message = "Filtered position statusIDs"
|
||||||
|
crumb2.data = [
|
||||||
|
"statusIDs": position.statusIDs,
|
||||||
|
]
|
||||||
|
SentrySDK.addBreadcrumb(crumb: crumb2)
|
||||||
|
|
||||||
return !position.statusIDs.isEmpty
|
return !position.statusIDs.isEmpty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@MainActor
|
||||||
private func applyItemsToRestore(position: TimelinePosition) {
|
private func applyItemsToRestore(position: TimelinePosition) {
|
||||||
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
|
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
|
||||||
snapshot.appendSections([.statuses])
|
snapshot.appendSections([.statuses])
|
||||||
|
@ -393,6 +421,12 @@ class TimelineViewController: UIViewController, TimelineLikeCollectionViewContro
|
||||||
let centerStatusID = position.centerStatusID
|
let centerStatusID = position.centerStatusID
|
||||||
let items = position.statusIDs.map { Item.status(id: $0, collapseState: .unknown, filterState: .unknown) }
|
let items = position.statusIDs.map { Item.status(id: $0, collapseState: .unknown, filterState: .unknown) }
|
||||||
snapshot.appendItems(items, toSection: .statuses)
|
snapshot.appendItems(items, toSection: .statuses)
|
||||||
|
let crumb = Breadcrumb(level: .info, category: "TimelineViewController")
|
||||||
|
crumb.message = "Restoring statuses"
|
||||||
|
crumb.data = [
|
||||||
|
"statusIDs": position.statusIDs
|
||||||
|
]
|
||||||
|
SentrySDK.addBreadcrumb(crumb: crumb)
|
||||||
dataSource.apply(snapshot, animatingDifferences: false) {
|
dataSource.apply(snapshot, animatingDifferences: false) {
|
||||||
if let centerStatusID,
|
if let centerStatusID,
|
||||||
let index = statusIDs.firstIndex(of: centerStatusID),
|
let index = statusIDs.firstIndex(of: centerStatusID),
|
||||||
|
@ -426,7 +460,12 @@ class TimelineViewController: UIViewController, TimelineLikeCollectionViewContro
|
||||||
|
|
||||||
private func filterResult(state: FilterState, statusID: String) -> (Filterer.Result, NSAttributedString?) {
|
private func filterResult(state: FilterState, statusID: String) -> (Filterer.Result, NSAttributedString?) {
|
||||||
let status = {
|
let status = {
|
||||||
let status = self.mastodonController.persistentContainer.status(for: statusID)!
|
guard let status = self.mastodonController.persistentContainer.status(for: statusID) else {
|
||||||
|
let crumb = Breadcrumb(level: .fatal, category: "TimelineViewController")
|
||||||
|
crumb.message = "Looking up status \(statusID)"
|
||||||
|
SentrySDK.addBreadcrumb(crumb: crumb)
|
||||||
|
preconditionFailure("Missing status for filtering")
|
||||||
|
}
|
||||||
// if the status is a reblog of another one, filter based on that one
|
// if the status is a reblog of another one, filter based on that one
|
||||||
if let reblogged = status.reblog {
|
if let reblogged = status.reblog {
|
||||||
return (reblogged, true)
|
return (reblogged, true)
|
||||||
|
|
Loading…
Reference in New Issue