Cleanup following the AppMediator introduction (#2723)

- stop using multiple background task, the appCoordinator sync one is enough for the whole app
- move the AppMeditor to the MainActor
- expose the WindowManager through the AppMediator
- hide sensitive WindowManager API behind a different protocol
- remove the now unnecessary `BackgroundTaskService`
This commit is contained in:
Stefan Ceriu
2024-04-22 18:10:24 +03:00
committed by GitHub
parent a3ec0b8505
commit 8ba544bc44
34 changed files with 117 additions and 929 deletions
@@ -1,37 +0,0 @@
//
// Copyright 2022 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.
//
import Foundation
typealias BackgroundTaskExpirationHandler = (BackgroundTaskProtocol) -> Void
/// BackgroundTaskProtocol is the protocol describing a background task regardless of the platform used.
protocol BackgroundTaskProtocol: AnyObject {
/// Name of the background task for debug.
var name: String { get }
/// `true` if the background task is currently running.
var isRunning: Bool { get }
/// Flag indicating the background task is reusable. If reusable, `name` is the key to distinguish background tasks.
var isReusable: Bool { get }
/// Method to be called when a task reused one more time. Should only be valid for reusable tasks.
func reuse()
/// Stop the background task. Cannot be started anymore. For reusable tasks, should be called same number of times `reuse` called.
func stop()
}
@@ -1,45 +0,0 @@
//
// Copyright 2022 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.
//
import Foundation
@MainActor
protocol BackgroundTaskServiceProtocol {
func startBackgroundTask(withName name: String,
isReusable: Bool,
expirationHandler: (() -> Void)?) -> BackgroundTaskProtocol?
}
extension BackgroundTaskServiceProtocol {
func startBackgroundTask(withName name: String) -> BackgroundTaskProtocol? {
startBackgroundTask(withName: name,
expirationHandler: nil)
}
func startBackgroundTask(withName name: String,
isReusable: Bool) -> BackgroundTaskProtocol? {
startBackgroundTask(withName: name,
isReusable: isReusable,
expirationHandler: nil)
}
func startBackgroundTask(withName name: String,
expirationHandler: (() -> Void)?) -> BackgroundTaskProtocol? {
startBackgroundTask(withName: name,
isReusable: false,
expirationHandler: expirationHandler)
}
}
@@ -1,95 +0,0 @@
//
// Copyright 2022 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.
//
import Foundation
import UIKit
class UIKitBackgroundTask: BackgroundTaskProtocol {
let name: String
var isRunning: Bool {
identifier != .invalid
}
let isReusable: Bool
let expirationHandler: BackgroundTaskExpirationHandler?
var elapsedTime: TimeInterval {
Date().timeIntervalSince(startDate) * 1000
}
private let appMediator: AppMediatorProtocol
private var identifier: UIBackgroundTaskIdentifier = .invalid
private var useCounter = 0
private let startDate = Date()
init?(name: String,
isReusable: Bool,
appMediator: AppMediatorProtocol,
expirationHandler: BackgroundTaskExpirationHandler?) {
self.name = name
self.isReusable = isReusable
self.appMediator = appMediator
self.expirationHandler = expirationHandler
identifier = appMediator.beginBackgroundTask(withName: name) { [weak self] in
guard let self else { return }
self.stop()
self.expirationHandler?(self)
}
if identifier == .invalid {
MXLog.error("Do not start background task: \(name), as OS declined")
expirationHandler?(self)
return nil
}
if isReusable {
reuse()
}
MXLog.verbose("Start background task #\(identifier.rawValue) - \(name)")
}
func reuse() {
guard isReusable else {
return
}
useCounter += 1
}
func stop() {
if isReusable {
useCounter -= 1
if useCounter <= 0 {
endTask()
}
} else {
endTask()
}
}
private func endTask() {
if identifier != .invalid {
MXLog.verbose("End background task #\(identifier.rawValue) - \(name) after \(readableElapsedTime)")
appMediator.endBackgroundTask(identifier)
identifier = .invalid
}
}
private var readableElapsedTime: String {
String(format: "%.3fms", elapsedTime)
}
}
@@ -1,98 +0,0 @@
//
// Copyright 2022 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.
//
import Foundation
import UIKit
/// /// UIKitBackgroundTaskService is a concrete implementation of BackgroundTaskServiceProtocol using a given `ApplicationProtocol` instance.
class UIKitBackgroundTaskService: BackgroundTaskServiceProtocol {
private let appMediator: AppMediatorProtocol
private var reusableTasks = NSMapTable<NSString, UIKitBackgroundTask>(keyOptions: .strongMemory, valueOptions: .weakMemory)
init(appMediator: AppMediatorProtocol) {
self.appMediator = appMediator
}
func startBackgroundTask(withName name: String,
isReusable: Bool,
expirationHandler: (() -> Void)?) -> BackgroundTaskProtocol? {
if shouldAvoidStartingNewTasks() {
MXLog.error("Do not start background task: \(name), as not enough time exists")
// call expiration handler immediately
expirationHandler?()
return nil
}
var created = false
var result: BackgroundTaskProtocol?
if isReusable {
if let oldTask = reusableTasks.object(forKey: name as NSString), oldTask.isRunning {
oldTask.reuse()
result = oldTask
} else {
if let newTask = UIKitBackgroundTask(name: name,
isReusable: isReusable,
appMediator: appMediator,
expirationHandler: { [weak self] task in
guard let self else { return }
self.reusableTasks.removeObject(forKey: task.name as NSString)
expirationHandler?()
}) {
created = true
reusableTasks.setObject(newTask, forKey: name as NSString)
result = newTask
}
}
} else {
if let newTask = UIKitBackgroundTask(name: name,
isReusable: isReusable,
appMediator: appMediator,
expirationHandler: { _ in
expirationHandler?()
}) {
result = newTask
created = true
}
}
let appState = appMediator.appState
let remainingTime = readableBackgroundTimeRemaining(appMediator.backgroundTimeRemaining)
MXLog.verbose("Background task \(name) \(created ? "started" : "reused") with app state: \(appState) and estimated background time remaining: \(remainingTime)")
return result
}
private func readableBackgroundTimeRemaining(_ backgroundTimeRemaining: TimeInterval) -> String {
if backgroundTimeRemaining == .greatestFiniteMagnitude {
return "undetermined"
} else {
return String(format: "%.0f seconds", backgroundTimeRemaining)
}
}
private func shouldAvoidStartingNewTasks() -> Bool {
if appMediator.appState == .background,
appMediator.backgroundTimeRemaining < .backgroundTimeRemainingThresholdToStartTasks {
return true
}
return false
}
}
private extension TimeInterval {
static let backgroundTimeRemainingThresholdToStartTasks: TimeInterval = 5
}
@@ -23,7 +23,6 @@ import MatrixRustSDK
class ClientProxy: ClientProxyProtocol {
private let client: ClientProtocol
private let backgroundTaskService: BackgroundTaskServiceProtocol
private let appSettings: AppSettings
private let networkMonitor: NetworkMonitorProtocol
@@ -122,11 +121,9 @@ class ClientProxy: ClientProxyProtocol {
}
init(client: ClientProtocol,
backgroundTaskService: BackgroundTaskServiceProtocol,
appSettings: AppSettings,
networkMonitor: NetworkMonitorProtocol) async {
self.client = client
self.backgroundTaskService = backgroundTaskService
self.appSettings = appSettings
self.networkMonitor = networkMonitor
@@ -134,8 +131,7 @@ class ClientProxy: ClientProxyProtocol {
mediaLoader = MediaLoader(client: client)
notificationSettings = NotificationSettingsProxy(notificationSettings: client.getNotificationSettings(),
backgroundTaskService: backgroundTaskService)
notificationSettings = NotificationSettingsProxy(notificationSettings: client.getNotificationSettings())
secureBackupController = SecureBackupController(encryption: client.encryption())
@@ -425,8 +421,7 @@ class ClientProxy: ClientProxyProtocol {
if let roomListItem, let room {
return await RoomProxy(roomListItem: roomListItem,
room: room,
backgroundTaskService: backgroundTaskService)
room: room)
}
// Else wait for the visible rooms list to go into fully loaded
@@ -453,8 +448,7 @@ class ClientProxy: ClientProxyProtocol {
}
return await RoomProxy(roomListItem: roomListItem,
room: room,
backgroundTaskService: backgroundTaskService)
room: room)
}
func roomPreviewForIdentifier(_ identifier: String) async -> Result<RoomPreviewDetails, ClientProxyError> {
@@ -20,14 +20,11 @@ import UIKit
struct MediaProvider: MediaProviderProtocol {
private let mediaLoader: MediaLoaderProtocol
private let imageCache: Kingfisher.ImageCache
private let backgroundTaskService: BackgroundTaskServiceProtocol?
init(mediaLoader: MediaLoaderProtocol,
imageCache: Kingfisher.ImageCache,
backgroundTaskService: BackgroundTaskServiceProtocol?) {
imageCache: Kingfisher.ImageCache) {
self.mediaLoader = mediaLoader
self.imageCache = imageCache
self.backgroundTaskService = backgroundTaskService
}
// MARK: Images
@@ -45,11 +42,6 @@ struct MediaProvider: MediaProviderProtocol {
return .success(image)
}
let loadImageBgTask = await backgroundTaskService?.startBackgroundTask(withName: "LoadImage: \(source.url.hashValue)")
defer {
loadImageBgTask?.stop()
}
let cacheKey = cacheKeyForURL(source.url, size: size)
if case let .success(cacheResult) = await imageCache.retrieveImage(forKey: cacheKey),
@@ -92,9 +84,6 @@ struct MediaProvider: MediaProviderProtocol {
// MARK: Files
func loadFileFromSource(_ source: MediaSourceProxy, body: String?) async -> Result<MediaFileHandleProxy, MediaProviderError> {
let loadFileBgTask = await backgroundTaskService?.startBackgroundTask(withName: "LoadFile: \(source.url.hashValue)")
defer { loadFileBgTask?.stop() }
do {
let file = try await mediaLoader.loadMediaFileForSource(source, body: body)
return .success(file)
@@ -36,13 +36,11 @@ private final class WeakNotificationSettingsProxy: NotificationSettingsDelegate
final class NotificationSettingsProxy: NotificationSettingsProxyProtocol {
private(set) var notificationSettings: MatrixRustSDK.NotificationSettingsProtocol
private let backgroundTaskService: BackgroundTaskServiceProtocol?
let callbacks = PassthroughSubject<NotificationSettingsProxyCallback, Never>()
init(notificationSettings: MatrixRustSDK.NotificationSettingsProtocol, backgroundTaskService: BackgroundTaskServiceProtocol?) {
init(notificationSettings: MatrixRustSDK.NotificationSettingsProtocol) {
self.notificationSettings = notificationSettings
self.backgroundTaskService = backgroundTaskService
notificationSettings.setDelegate(delegate: WeakNotificationSettingsProxy(proxy: self))
}
@@ -52,9 +50,6 @@ final class NotificationSettingsProxy: NotificationSettingsProxyProtocol {
}
func setNotificationMode(roomId: String, mode: RoomNotificationModeProxy) async throws {
let backgroundTask = await backgroundTaskService?.startBackgroundTask(withName: "setNotificationMode")
defer { backgroundTask?.stop() }
try await notificationSettings.setRoomNotificationMode(roomId: roomId, mode: mode.roomNotificationMode)
await updatedSettings()
}
@@ -70,9 +65,6 @@ final class NotificationSettingsProxy: NotificationSettingsProxyProtocol {
}
func setDefaultRoomNotificationMode(isEncrypted: Bool, isOneToOne: Bool, mode: RoomNotificationModeProxy) async throws {
let backgroundTask = await backgroundTaskService?.startBackgroundTask(withName: "setDefaultRoomNotificationMode")
defer { backgroundTask?.stop() }
do {
try await notificationSettings.setDefaultRoomNotificationMode(isEncrypted: isEncrypted, isOneToOne: isOneToOne, mode: mode.roomNotificationMode)
} catch NotificationSettingsError.RuleNotFound(let ruleId) {
@@ -86,17 +78,11 @@ final class NotificationSettingsProxy: NotificationSettingsProxyProtocol {
}
func restoreDefaultNotificationMode(roomId: String) async throws {
let backgroundTask = await backgroundTaskService?.startBackgroundTask(withName: "restoreDefaultNotificationMode")
defer { backgroundTask?.stop() }
try await notificationSettings.restoreDefaultRoomNotificationMode(roomId: roomId)
await updatedSettings()
}
func unmuteRoom(roomId: String, isEncrypted: Bool, isOneToOne: Bool) async throws {
let backgroundTask = await backgroundTaskService?.startBackgroundTask(withName: "unmuteRoom")
defer { backgroundTask?.stop() }
try await notificationSettings.unmuteRoom(roomId: roomId, isEncrypted: isEncrypted, isOneToOne: isOneToOne)
await updatedSettings()
}
@@ -106,9 +92,6 @@ final class NotificationSettingsProxy: NotificationSettingsProxyProtocol {
}
func setRoomMentionEnabled(enabled: Bool) async throws {
let backgroundTask = await backgroundTaskService?.startBackgroundTask(withName: "setRoomMentionEnabled")
defer { backgroundTask?.stop() }
try await notificationSettings.setRoomMentionEnabled(enabled: enabled)
await updatedSettings()
}
@@ -118,9 +101,6 @@ final class NotificationSettingsProxy: NotificationSettingsProxyProtocol {
}
func setCallEnabled(enabled: Bool) async throws {
let backgroundTask = await backgroundTaskService?.startBackgroundTask(withName: "setCallEnabled")
defer { backgroundTask?.stop() }
try await notificationSettings.setCallEnabled(enabled: enabled)
await updatedSettings()
}
@@ -130,9 +110,6 @@ final class NotificationSettingsProxy: NotificationSettingsProxyProtocol {
}
func setInviteForMeEnabled(enabled: Bool) async throws {
let backgroundTask = await backgroundTaskService?.startBackgroundTask(withName: "setInviteForMeEnabled")
defer { backgroundTask?.stop() }
try await notificationSettings.setInviteForMeEnabled(enabled: enabled)
await updatedSettings()
}
+8 -33
View File
@@ -26,13 +26,9 @@ class RoomProxy: RoomProxyProtocol {
private let roomListItem: RoomListItemProtocol
private let room: RoomProtocol
let timeline: TimelineProxyProtocol
private let backgroundTaskService: BackgroundTaskServiceProtocol
private let backgroundTaskName = "SendRoomEvent"
private let userInitiatedDispatchQueue = DispatchQueue(label: "io.element.elementx.roomproxy.user_initiated", qos: .userInitiated)
private var sendMessageBackgroundTask: BackgroundTaskProtocol?
// periphery:ignore - required for instance retention in the rust codebase
private var roomInfoObservationToken: TaskHandle?
// periphery:ignore - required for instance retention in the rust codebase
@@ -60,13 +56,12 @@ class RoomProxy: RoomProxyProtocol {
}
init?(roomListItem: RoomListItemProtocol,
room: RoomProtocol,
backgroundTaskService: BackgroundTaskServiceProtocol) async {
room: RoomProtocol) async {
self.roomListItem = roomListItem
self.room = room
self.backgroundTaskService = backgroundTaskService
do {
timeline = try await TimelineProxy(timeline: room.timeline(), backgroundTaskService: backgroundTaskService)
timeline = try await TimelineProxy(timeline: room.timeline())
} catch {
MXLog.error("Failed creating timeline with error: \(error)")
return nil
@@ -165,12 +160,7 @@ class RoomProxy: RoomProxyProtocol {
}
func redact(_ eventID: String) async -> Result<Void, RoomProxyError> {
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
defer {
sendMessageBackgroundTask?.stop()
}
return await Task.dispatch(on: userInitiatedDispatchQueue) {
await Task.dispatch(on: userInitiatedDispatchQueue) {
do {
try self.room.redact(eventId: eventID, reason: nil)
return .success(())
@@ -180,14 +170,9 @@ class RoomProxy: RoomProxyProtocol {
}
}
}
func reportContent(_ eventID: String, reason: String?) async -> Result<Void, RoomProxyError> {
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
defer {
sendMessageBackgroundTask?.stop()
}
return await Task.dispatch(on: userInitiatedDispatchQueue) {
await Task.dispatch(on: userInitiatedDispatchQueue) {
do {
try self.room.reportContent(eventId: eventID, score: nil, reason: reason)
return .success(())
@@ -226,11 +211,6 @@ class RoomProxy: RoomProxyProtocol {
return .success(member)
}
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
defer {
sendMessageBackgroundTask?.stop()
}
do {
let member = try await room.member(userId: userID)
return .success(RoomMemberProxy(member: member))
@@ -239,14 +219,9 @@ class RoomProxy: RoomProxyProtocol {
return .failure(.sdkError(error))
}
}
func leaveRoom() async -> Result<Void, RoomProxyError> {
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
defer {
sendMessageBackgroundTask?.stop()
}
return await Task.dispatch(on: .global()) {
await Task.dispatch(on: .global()) {
do {
try self.room.leave()
return .success(())
@@ -20,10 +20,7 @@ import MatrixRustSDK
final class TimelineProxy: TimelineProxyProtocol {
private let timeline: Timeline
private var sendMessageBackgroundTask: BackgroundTaskProtocol?
private let backgroundTaskService: BackgroundTaskServiceProtocol
private let backgroundTaskName = "SendRoomEvent"
private let lowPriorityDispatchQueue = DispatchQueue(label: "io.element.elementx.roomproxy.low_priority", qos: .utility)
private let messageSendingDispatchQueue = DispatchQueue(label: "io.element.elementx.roomproxy.message_sending", qos: .userInitiated)
private let userInitiatedDispatchQueue = DispatchQueue(label: "io.element.elementx.roomproxy.user_initiated", qos: .userInitiated)
@@ -54,9 +51,8 @@ final class TimelineProxy: TimelineProxyProtocol {
roomTimelineObservationToken?.cancel()
}
init(timeline: Timeline, backgroundTaskService: BackgroundTaskServiceProtocol) {
init(timeline: Timeline) {
self.timeline = timeline
self.backgroundTaskService = backgroundTaskService
}
func subscribeForUpdates() async {
@@ -84,11 +80,6 @@ final class TimelineProxy: TimelineProxyProtocol {
func cancelSend(transactionID: String) async {
MXLog.info("Cancelling sending for transaction ID: \(transactionID)")
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
defer {
sendMessageBackgroundTask?.stop()
}
return await Task.dispatch(on: messageSendingDispatchQueue) {
self.timeline.cancelSend(txnId: transactionID)
MXLog.info("Finished cancelling sending for transaction ID: \(transactionID)")
@@ -101,11 +92,6 @@ final class TimelineProxy: TimelineProxyProtocol {
intentionalMentions: IntentionalMentions) async -> Result<Void, TimelineProxyError> {
MXLog.info("Editing message with original event ID: \(eventID)")
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
defer {
sendMessageBackgroundTask?.stop()
}
let messageContent = buildMessageContentFor(message,
html: html,
intentionalMentions: intentionalMentions.toRustMentions())
@@ -198,11 +184,6 @@ final class TimelineProxy: TimelineProxyProtocol {
func retrySend(transactionID: String) async {
MXLog.info("Retrying sending for transactionID: \(transactionID)")
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
defer {
sendMessageBackgroundTask?.stop()
}
return await Task.dispatch(on: messageSendingDispatchQueue) {
self.timeline.retrySend(txnId: transactionID)
MXLog.info("Finished retrying sending for transactionID: \(transactionID)")
@@ -215,11 +196,6 @@ final class TimelineProxy: TimelineProxyProtocol {
requestHandle: @MainActor (SendAttachmentJoinHandleProtocol) -> Void) async -> Result<Void, TimelineProxyError> {
MXLog.info("Sending audio")
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
defer {
sendMessageBackgroundTask?.stop()
}
let handle = timeline.sendAudio(url: url.path(percentEncoded: false), audioInfo: audioInfo, caption: nil, formattedCaption: nil, progressWatcher: UploadProgressListener { progress in
progressSubject?.send(progress)
})
@@ -245,11 +221,6 @@ final class TimelineProxy: TimelineProxyProtocol {
requestHandle: @MainActor (SendAttachmentJoinHandleProtocol) -> Void) async -> Result<Void, TimelineProxyError> {
MXLog.info("Sending file")
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
defer {
sendMessageBackgroundTask?.stop()
}
let handle = timeline.sendFile(url: url.path(percentEncoded: false), fileInfo: fileInfo, progressWatcher: UploadProgressListener { progress in
progressSubject?.send(progress)
})
@@ -276,11 +247,6 @@ final class TimelineProxy: TimelineProxyProtocol {
requestHandle: @MainActor (SendAttachmentJoinHandleProtocol) -> Void) async -> Result<Void, TimelineProxyError> {
MXLog.info("Sending image")
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
defer {
sendMessageBackgroundTask?.stop()
}
let handle = timeline.sendImage(url: url.path(percentEncoded: false), thumbnailUrl: thumbnailURL.path(percentEncoded: false), imageInfo: imageInfo, caption: nil, formattedCaption: nil, progressWatcher: UploadProgressListener { progress in
progressSubject?.send(progress)
})
@@ -307,11 +273,6 @@ final class TimelineProxy: TimelineProxyProtocol {
assetType: AssetType?) async -> Result<Void, TimelineProxyError> {
MXLog.info("Sending location")
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
defer {
sendMessageBackgroundTask?.stop()
}
return await Task.dispatch(on: messageSendingDispatchQueue) {
self.timeline.sendLocation(body: body,
geoUri: geoURI.string,
@@ -334,11 +295,6 @@ final class TimelineProxy: TimelineProxyProtocol {
requestHandle: @MainActor (SendAttachmentJoinHandleProtocol) -> Void) async -> Result<Void, TimelineProxyError> {
MXLog.info("Sending video")
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
defer {
sendMessageBackgroundTask?.stop()
}
let handle = timeline.sendVideo(url: url.path(percentEncoded: false), thumbnailUrl: thumbnailURL.path(percentEncoded: false), videoInfo: videoInfo, caption: nil, formattedCaption: nil, progressWatcher: UploadProgressListener { progress in
progressSubject?.send(progress)
})
@@ -365,11 +321,6 @@ final class TimelineProxy: TimelineProxyProtocol {
requestHandle: @MainActor (SendAttachmentJoinHandleProtocol) -> Void) async -> Result<Void, TimelineProxyError> {
MXLog.info("Sending voice message")
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
defer {
sendMessageBackgroundTask?.stop()
}
let handle = timeline.sendVoiceMessage(url: url.path(percentEncoded: false), audioInfo: audioInfo, waveform: waveform, caption: nil, formattedCaption: nil, progressWatcher: UploadProgressListener { progress in
progressSubject?.send(progress)
})
@@ -399,11 +350,6 @@ final class TimelineProxy: TimelineProxyProtocol {
MXLog.info("Sending message")
}
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
defer {
sendMessageBackgroundTask?.stop()
}
let messageContent = buildMessageContentFor(message,
html: html,
intentionalMentions: intentionalMentions.toRustMentions())
@@ -436,12 +382,7 @@ final class TimelineProxy: TimelineProxyProtocol {
func sendMessageEventContent(_ messageContent: RoomMessageEventContentWithoutRelation) async -> Result<Void, TimelineProxyError> {
MXLog.info("Sending message content")
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
defer {
sendMessageBackgroundTask?.stop()
}
return await Task.dispatch(on: messageSendingDispatchQueue) {
self.timeline.send(msg: messageContent)
@@ -456,11 +397,6 @@ final class TimelineProxy: TimelineProxyProtocol {
func sendReadReceipt(for eventID: String, type: ReceiptType) async -> Result<Void, TimelineProxyError> {
MXLog.verbose("Sending read receipt for eventID: \(eventID)")
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
defer {
sendMessageBackgroundTask?.stop()
}
return await Task.dispatch(on: lowPriorityDispatchQueue) {
do {
try self.timeline.sendReadReceipt(receiptType: type, eventId: eventID)
@@ -476,11 +412,6 @@ final class TimelineProxy: TimelineProxyProtocol {
func toggleReaction(_ reaction: String, to eventID: String) async -> Result<Void, TimelineProxyError> {
MXLog.info("Toggling reaction for eventID: \(eventID)")
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
defer {
sendMessageBackgroundTask?.stop()
}
return await Task.dispatch(on: userInitiatedDispatchQueue) {
do {
try self.timeline.toggleReaction(eventId: eventID, key: reaction)
@@ -20,7 +20,6 @@ import MatrixRustSDK
class UserSessionStore: UserSessionStoreProtocol {
private let keychainController: KeychainControllerProtocol
private let backgroundTaskService: BackgroundTaskServiceProtocol
private let matrixSDKStateKey = "matrix-sdk-state"
/// Whether or not there are sessions in the store.
@@ -33,9 +32,8 @@ class UserSessionStore: UserSessionStoreProtocol {
var clientSessionDelegate: ClientSessionDelegate { keychainController }
init(keychainController: KeychainControllerProtocol, backgroundTaskService: BackgroundTaskServiceProtocol) {
init(keychainController: KeychainControllerProtocol) {
self.keychainController = keychainController
self.backgroundTaskService = backgroundTaskService
baseDirectory = .sessionsBaseDirectory
MXLog.info("Setup base directory at: \(baseDirectory)")
}
@@ -100,11 +98,9 @@ class UserSessionStore: UserSessionStoreProtocol {
private func buildUserSessionWithClient(_ clientProxy: ClientProxyProtocol) -> UserSessionProtocol {
let mediaProvider = MediaProvider(mediaLoader: clientProxy,
imageCache: .onlyInMemory,
backgroundTaskService: backgroundTaskService)
imageCache: .onlyInMemory)
let voiceMessageMediaManager = VoiceMessageMediaManager(mediaProvider: mediaProvider,
backgroundTaskService: backgroundTaskService)
let voiceMessageMediaManager = VoiceMessageMediaManager(mediaProvider: mediaProvider)
return UserSession(clientProxy: clientProxy,
mediaProvider: mediaProvider,
@@ -150,7 +146,6 @@ class UserSessionStore: UserSessionStoreProtocol {
private func setupProxyForClient(_ client: Client) async -> ClientProxyProtocol {
await ClientProxy(client: client,
backgroundTaskService: backgroundTaskService,
appSettings: ServiceLocator.shared.settings,
networkMonitor: ServiceLocator.shared.networkMonitor)
}
@@ -30,7 +30,6 @@ class VoiceMessageMediaManager: VoiceMessageMediaManagerProtocol {
private let voiceMessageCache: VoiceMessageCacheProtocol
private let audioConverter: AudioConverterProtocol
private let backgroundTaskService: BackgroundTaskServiceProtocol?
private let processingQueue: DispatchQueue
private var conversionRequests = [MediaSourceProxy: VoiceMessageConversionRequest]()
@@ -39,13 +38,11 @@ class VoiceMessageMediaManager: VoiceMessageMediaManagerProtocol {
init(mediaProvider: MediaProviderProtocol,
voiceMessageCache: VoiceMessageCacheProtocol = VoiceMessageCache(),
audioConverter: AudioConverterProtocol = AudioConverter(),
processingQueue: DispatchQueue = .global(),
backgroundTaskService: BackgroundTaskServiceProtocol?) {
processingQueue: DispatchQueue = .global()) {
self.mediaProvider = mediaProvider
self.voiceMessageCache = voiceMessageCache
self.audioConverter = audioConverter
self.processingQueue = processingQueue
self.backgroundTaskService = backgroundTaskService
}
deinit {
@@ -53,9 +50,6 @@ class VoiceMessageMediaManager: VoiceMessageMediaManagerProtocol {
}
func loadVoiceMessageFromSource(_ source: MediaSourceProxy, body: String?) async throws -> URL {
let loadFileBgTask = await backgroundTaskService?.startBackgroundTask(withName: "LoadFile: \(source.url.hashValue)")
defer { loadFileBgTask?.stop() }
guard let mimeType = source.mimeType, mimeType.starts(with: supportedVoiceMessageMimeType) else {
throw VoiceMessageMediaManagerError.unsupportedMimeTye
}