Skip to content

Commit

Permalink
Synchronize access to the new NSE user session property
Browse files Browse the repository at this point in the history
  • Loading branch information
stefanceriu committed Jun 19, 2024
1 parent f291f10 commit 23b0cde
Showing 1 changed file with 33 additions and 8 deletions.
41 changes: 33 additions & 8 deletions NSE/Sources/NotificationServiceExtension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,9 @@ 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,
withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
guard !DataProtectionManager.isDeviceLockedAfterReboot(containerURL: URL.appGroupContainerDirectory),
Expand All @@ -76,19 +77,26 @@ class NotificationServiceExtension: UNNotificationServiceExtension {
MXLog.info("\(tag) #########################################")
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
do {
Self.userSession = try await NSEUserSession(credentials: credentials, clientSessionDelegate: keychainController)
} catch {
MXLog.error("NSE run error: \(error)")
return discard(unreadCount: request.unreadCount)
Task.synchronous {
do {
Self.userSession = try await NSEUserSession(credentials: credentials, clientSessionDelegate: keychainController)
} catch {
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,
Expand Down Expand Up @@ -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()
}
}

0 comments on commit 23b0cde

Please sign in to comment.