Synchronize access to the new NSE user session property

This commit is contained in:
Stefan Ceriu 2024-06-19 17:49:56 +03:00 committed by Stefan Ceriu
parent f291f10f46
commit 23b0cde845

View File

@ -51,6 +51,7 @@ class NotificationServiceExtension: UNNotificationServiceExtension {
private var modifiedContent: UNMutableNotificationContent?
// Used to create one single UserSession across process/instances/runs
private static let serialQueue = DispatchQueue(label: "io.element.elementx.nse")
private static var userSession: NSEUserSession?
override func didReceive(_ request: UNNotificationRequest,
@ -77,18 +78,25 @@ class NotificationServiceExtension: UNNotificationServiceExtension {
NSELogger.logMemory(with: tag)
MXLog.info("\(tag) Payload came: \(request.content.userInfo)")
Task {
Self.serialQueue.sync {
if Self.userSession == nil {
// This function might be run concurrently and from different processes
// It's imperative that we create **at most** one UserSession/Client per process
Task.synchronous {
do {
Self.userSession = try await NSEUserSession(credentials: credentials, clientSessionDelegate: keychainController)
} catch {
MXLog.error("NSE run error: \(error)")
MXLog.error("Failed creating user session with error: \(error)")
}
}
}
if Self.userSession == nil {
return discard(unreadCount: request.unreadCount)
}
}
Task {
await run(with: credentials,
roomId: roomId,
eventId: eventId,
@ -234,3 +242,20 @@ class NotificationServiceExtension: UNNotificationServiceExtension {
return false
}
}
// https://stackoverflow.com/a/77300959/730924
private extension Task where Failure == Error {
/// Performs an async task in a sync context.
///
/// - Note: This function blocks the thread until the given operation is finished. The caller is responsible for managing multithreading.
static func synchronous(priority: TaskPriority? = nil, operation: @escaping @Sendable () async throws -> Success) {
let semaphore = DispatchSemaphore(value: 0)
Task(priority: priority) {
defer { semaphore.signal() }
return try await operation()
}
semaphore.wait()
}
}