Concurrency Fixes (#283)

* Review places where MainActor used

* Adapt to MainActor changes, avoid redundant task detachments

* Move Rust client operations into a dedicated concurrent queue, make init async

* Add changelog

* Fixed small working for awaiting non-async method

* Remove some redundant tasks

* Put back some main actors

* Fix tests

* Fixed timeline updates when the number of items doesn't change. Keeps more previous home screen room data between reloads

Co-authored-by: Stefan Ceriu <stefanc@matrix.org>
This commit is contained in:
ismailgulek
2022-11-02 18:25:46 +03:00
committed by GitHub
parent 965569aae2
commit f6a599a51b
19 changed files with 243 additions and 221 deletions
@@ -55,43 +55,38 @@ struct MediaProvider: MediaProviderProtocol {
return .success(image)
}
let loadImageBgTask = backgroundTaskService.startBackgroundTask(withName: "LoadImage: \(source.underlyingSource.url().hashValue)")
let loadImageBgTask = await backgroundTaskService.startBackgroundTask(withName: "LoadImage: \(source.url.hashValue)")
defer {
loadImageBgTask?.stop()
}
let cacheKey = cacheKeyForURLString(source.underlyingSource.url(), avatarSize: avatarSize)
return await Task.detached { () -> Result<UIImage, MediaProviderError> in
if case let .success(cacheResult) = await imageCache.retrieveImage(forKey: cacheKey),
let image = cacheResult.image {
return .success(image)
}
do {
let imageData = try await Task.detached { () -> Data in
if let avatarSize {
return try await clientProxy.loadMediaThumbnailForSource(source.underlyingSource, width: UInt(avatarSize.scaledValue), height: UInt(avatarSize.scaledValue))
} else {
return try await clientProxy.loadMediaContentForSource(source.underlyingSource)
}
}.value
guard let image = UIImage(data: imageData) else {
MXLog.error("Invalid image data")
return .failure(.invalidImageData)
}
imageCache.store(image, forKey: cacheKey)
return .success(image)
} catch {
MXLog.error("Failed retrieving image with error: \(error)")
return .failure(.failedRetrievingImage)
}
let cacheKey = cacheKeyForURLString(source.url, avatarSize: avatarSize)
if case let .success(cacheResult) = await imageCache.retrieveImage(forKey: cacheKey),
let image = cacheResult.image {
return .success(image)
}
do {
let imageData: Data
if let avatarSize {
imageData = try await clientProxy.loadMediaThumbnailForSource(source.underlyingSource, width: UInt(avatarSize.scaledValue), height: UInt(avatarSize.scaledValue))
} else {
imageData = try await clientProxy.loadMediaContentForSource(source.underlyingSource)
}
guard let image = UIImage(data: imageData) else {
MXLog.error("Invalid image data")
return .failure(.invalidImageData)
}
imageCache.store(image, forKey: cacheKey)
return .success(image)
} catch {
MXLog.error("Failed retrieving image with error: \(error)")
return .failure(.failedRetrievingImage)
}
.value
}
// MARK: - Private
@@ -22,7 +22,6 @@ enum MediaProviderError: Error {
case invalidImageData
}
@MainActor
protocol MediaProviderProtocol {
func imageFromSource(_ source: MediaSource?, avatarSize: AvatarSize?) -> UIImage?
@@ -19,6 +19,10 @@ import MatrixRustSDK
struct MediaSource: Equatable {
let underlyingSource: MatrixRustSDK.MediaSource
var url: String {
underlyingSource.url()
}
init(source: MatrixRustSDK.MediaSource) {
underlyingSource = source