Fixed a few PN behaviours

• Tweaked the message request notification behaviour
• Fixed an issue where duplicate message errors would result in the generic notification being shown
• Further notification logging improvements
pull/986/head
Morgan Pretty 10 months ago
parent db796896f4
commit 185e84dc95

@ -8042,7 +8042,7 @@
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
CURRENT_PROJECT_VERSION = 453;
CURRENT_PROJECT_VERSION = 454;
ENABLE_BITCODE = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
@ -8120,7 +8120,7 @@
CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "iPhone Distribution";
CURRENT_PROJECT_VERSION = 453;
CURRENT_PROJECT_VERSION = 454;
ENABLE_BITCODE = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_NO_COMMON_BLOCKS = YES;

@ -235,6 +235,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
Log.info("[AppDelegate] applicationDidBecomeActive.")
guard !SNUtilitiesKit.isRunningTests else { return }
Log.info("[AppDelegate] Setting 'isMainAppActive' to true.")
UserDefaults.sharedLokiProject?[.isMainAppActive] = true
ensureRootViewController(calledFrom: .didBecomeActive)
@ -263,6 +264,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
Log.info("[AppDelegate] applicationWillResignActive.")
clearAllNotificationsAndRestoreBadgeCount()
Log.info("[AppDelegate] Setting 'isMainAppActive' to false.")
UserDefaults.sharedLokiProject?[.isMainAppActive] = false
Log.flush()

@ -488,24 +488,11 @@ public extension SessionThread {
// If the thread is a message request then we only want to notify for the first message
if self.variant == .contact && isMessageRequest {
let hasHiddenMessageRequests: Bool = db[.hasHiddenMessageRequests]
// If the user hasn't hidden the message requests section then only show the notification if
// all the other message request threads have been read
if !hasHiddenMessageRequests {
let numUnreadMessageRequestThreads: Int = (try? SessionThread
.unreadMessageRequestsCountQuery(userPublicKey: userPublicKey, includeNonVisible: true)
.fetchOne(db))
.defaulting(to: 1)
guard numUnreadMessageRequestThreads == 1 else { return false }
}
// We only want to show a notification for the first interaction in the thread
guard ((try? self.interactions.fetchCount(db)) ?? 0) <= 1 else { return false }
// Need to re-show the message requests section if it had been hidden
if hasHiddenMessageRequests {
if db[.hasHiddenMessageRequests] {
db[.hasHiddenMessageRequests] = false
}
}

@ -19,7 +19,6 @@ public enum MessageReceiverError: LocalizedError {
case noThread
case selfSend
case decryptionFailed
case invalidGroupPublicKey
case noGroupKeyPair
case invalidConfigMessageHandling
case requiredThreadNotInConfig
@ -68,7 +67,6 @@ public enum MessageReceiverError: LocalizedError {
case .decryptionFailed: return "Decryption failed."
// Shared sender keys
case .invalidGroupPublicKey: return "Invalid group public key."
case .noGroupKeyPair: return "Missing group key pair."
case .invalidConfigMessageHandling: return "Invalid handling of a config message."

@ -15,6 +15,7 @@ public class NSENotificationPresenter: NSObject, NotificationsProtocol {
// Ensure we should be showing a notification for the thread
guard thread.shouldShowNotification(db, for: interaction, isMessageRequest: isMessageRequest) else {
Log.info("Ignoring notification because thread reported that we shouldn't show it.")
return
}

@ -17,8 +17,8 @@ enum NotificationError: Error, CustomStringConvertible {
case .processing(let result): return "Failed to process notification (\(result)) (NotificationError.processing)."
case .messageProcessing: return "Failed to process message (NotificationError.messageProcessing)."
case .ignorableMessage: return "Ignorable message (NotificationError.ignorableMessage)."
case .messageHandling(let error): return "Failed to handle message (\(error)) (NotificationError.messageHandling)."
case .other(let error): return "Unknown error occurred: \(error) (NotificationError.other)."
case .messageHandling(let error): return "Failed to handle message (\("\(error)".noPeriod)) (NotificationError.messageHandling)."
case .other(let error): return "Unknown error occurred: \("\(error)".noPeriod)) (NotificationError.other)."
}
}
}

@ -36,12 +36,12 @@ public final class NotificationServiceExtension: UNNotificationServiceExtension
// Abort if the main app is running
guard !(UserDefaults.sharedLokiProject?[.isMainAppActive]).defaulting(to: false) else {
Log.info("didReceive called while main app running.")
return self.completeSilenty(isMainAppAndActive: true)
return self.completeSilenty(handledNotification: false, isMainAppAndActive: true)
}
guard let notificationContent = request.content.mutableCopy() as? UNMutableNotificationContent else {
Log.info("didReceive called with no content.")
return self.completeSilenty()
return self.completeSilenty(handledNotification: false)
}
Log.info("didReceive called.")
@ -69,7 +69,7 @@ public final class NotificationServiceExtension: UNNotificationServiceExtension
guard metadata.accountId == getUserHexEncodedPublicKey(using: dependencies) else {
guard !isPerformingResetup else {
Log.error("Received notification for an accountId that isn't the current user, resetup failed.")
return self.completeSilenty()
return self.completeSilenty(handledNotification: false)
}
Log.warn("Received notification for an accountId that isn't the current user, attempting to resetup.")
@ -90,9 +90,15 @@ public final class NotificationServiceExtension: UNNotificationServiceExtension
// these will most commonly be call or config messages)
case .successTooLong:
Log.info("Received too long notification for namespace: \(metadata.namespace), dataLength: \(metadata.dataLength).")
return self.completeSilenty()
return self.completeSilenty(handledNotification: false)
case .legacyForceSilent, .failureNoContent: return self.completeSilenty()
case .legacyForceSilent:
Log.info("Ignoring non-group legacy notification.")
return self.completeSilenty(handledNotification: false)
case .failureNoContent:
Log.warn("Failed due to missing notification content.")
return self.completeSilenty(handledNotification: false)
}
}
@ -189,6 +195,15 @@ public final class NotificationServiceExtension: UNNotificationServiceExtension
case (true, false):
try MessageReceiver.insertCallInfoMessage(db, for: callMessage)
// Perform any required post-handling logic
try MessageReceiver.postHandleMessage(
db,
threadId: threadId,
threadVariant: threadVariant,
message: messageInfo.message
)
return self?.handleSuccessForIncomingCall(db, for: callMessage)
}
@ -213,8 +228,8 @@ public final class NotificationServiceExtension: UNNotificationServiceExtension
}
db.afterNextTransaction(
onCommit: { _ in self?.completeSilenty() },
onRollback: { _ in self?.completeSilenty() }
onCommit: { _ in self?.completeSilenty(handledNotification: true) },
onRollback: { _ in self?.completeSilenty(handledNotification: false) }
)
}
catch {
@ -222,9 +237,22 @@ public final class NotificationServiceExtension: UNNotificationServiceExtension
// the error outside of the database
let handleError = {
switch error {
case MessageReceiverError.invalidGroupPublicKey, MessageReceiverError.noGroupKeyPair,
MessageReceiverError.outdatedMessage, NotificationError.ignorableMessage:
self?.completeSilenty()
case MessageReceiverError.noGroupKeyPair:
Log.warn("Failed due to having no legacy group decryption keys.")
self?.completeSilenty(handledNotification: false)
case MessageReceiverError.outdatedMessage:
Log.info("Ignoring notification for already seen message.")
self?.completeSilenty(handledNotification: false)
case NotificationError.ignorableMessage:
Log.info("Ignoring message which requires no notification.")
self?.completeSilenty(handledNotification: false)
case MessageReceiverError.duplicateMessage, MessageReceiverError.duplicateControlMessage,
MessageReceiverError.duplicateMessageNewSnode:
Log.info("Ignoring duplicate message (probably received it just before going to the background).")
self?.completeSilenty(handledNotification: false)
case NotificationError.messageProcessing:
self?.handleFailure(for: notificationContent, error: .messageProcessing)
@ -282,7 +310,7 @@ public final class NotificationServiceExtension: UNNotificationServiceExtension
switch result {
case .failure(let error):
Log.error("Failed to complete migrations: \(error).")
self?.completeSilenty()
self?.completeSilenty(handledNotification: false)
case .success:
// We should never receive a non-voip notification on an app that doesn't support
@ -292,7 +320,7 @@ public final class NotificationServiceExtension: UNNotificationServiceExtension
// and don't disturb the user. Messages will be processed when they open the app.
guard Storage.shared[.isReadyForAppExtensions] else {
Log.error("Not ready for extensions.")
self?.completeSilenty()
self?.completeSilenty(handledNotification: false)
return
}
@ -317,7 +345,7 @@ public final class NotificationServiceExtension: UNNotificationServiceExtension
// App isn't ready until storage is ready AND all version migrations are complete.
guard Storage.shared.isValid else {
Log.error("Storage invalid.")
return self.completeSilenty()
return self.completeSilenty(handledNotification: false)
}
// If the app wasn't ready then mark it as ready now
@ -363,10 +391,10 @@ public final class NotificationServiceExtension: UNNotificationServiceExtension
// Called just before the extension will be terminated by the system.
// Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
Log.warn("Execution time expired.")
completeSilenty()
completeSilenty(handledNotification: false)
}
private func completeSilenty(isMainAppAndActive: Bool = false) {
private func completeSilenty(handledNotification: Bool, isMainAppAndActive: Bool = false) {
// Ensure we only run this once
guard
hasCompleted.mutate({ hasCompleted in
@ -382,7 +410,7 @@ public final class NotificationServiceExtension: UNNotificationServiceExtension
.map { NSNumber(value: $0) }
.defaulting(to: NSNumber(value: 0))
Log.info("Complete silently.")
Log.info(handledNotification ? "Completed after handling notification." : "Completed silently.")
if !isMainAppAndActive {
Storage.suspendDatabaseAccess()
}
@ -412,7 +440,7 @@ public final class NotificationServiceExtension: UNNotificationServiceExtension
else {
Log.info("Successfully notified main app of call message.")
UserDefaults.sharedLokiProject?[.lastCallPreOffer] = Date()
self?.completeSilenty()
self?.completeSilenty(handledNotification: true)
}
}
}
@ -457,8 +485,8 @@ public final class NotificationServiceExtension: UNNotificationServiceExtension
Log.info("Add remote notification request.")
db.afterNextTransaction(
onCommit: { [weak self] _ in self?.completeSilenty() },
onRollback: { [weak self] _ in self?.completeSilenty() }
onCommit: { [weak self] _ in self?.completeSilenty(handledNotification: true) },
onRollback: { [weak self] _ in self?.completeSilenty(handledNotification: false) }
)
}

@ -377,11 +377,11 @@ public class Logger {
#if DEBUG
print(logMessage)
#endif
#else
if forceNSLog {
NSLog(message)
}
#endif
}
}
@ -416,7 +416,7 @@ private extension DispatchQueue {
}
}
// FIXME: Remove this once everything has been updated to use the new `Log.x()` methods
// FIXME: Remove this once everything has been updated to use the new `Log.x()` methods.
public func SNLog(_ message: String, forceNSLog: Bool = false) {
Log.info(message)
}

@ -77,6 +77,14 @@ public extension String {
// MARK: - Formatting
public extension String {
var noPeriod: String {
guard self.hasSuffix(".") && !self.hasSuffix("...") else { return self }
return String(self.prefix(count - 1))
}
}
public extension String.StringInterpolation {
mutating func appendInterpolation(plural value: Int) {
appendInterpolation(value == 1 ? "" : "s") // stringlint:disable

@ -1633,7 +1633,7 @@ public final class JobQueue: Hashable {
// immediately (in this case we don't trigger any job callbacks because the
// job isn't actually done, it's going to try again immediately)
if self.type == .blocking && job.shouldBlock {
SNLog("[JobRunner] \(queueContext) \(job.variant) job failed due to error: \(error ?? JobRunnerError.unknown); retrying immediately")
SNLog("[JobRunner] \(queueContext) \(job.variant) job failed due to error: \("\(error ?? JobRunnerError.unknown)".noPeriod); retrying immediately")
// If it was a possible deferral loop then we don't actually want to
// retry the job (even if it's a blocking one, this gives a small chance

Loading…
Cancel
Save