Handle expiration timer updates
This commit is contained in:
parent
7e9eb2f138
commit
97545de75e
|
@ -206,21 +206,21 @@ extension Storage : SessionMessagingKitStorageProtocol {
|
|||
}
|
||||
|
||||
public func updateProfile(for publicKey: String, from profile: VisibleMessage.Profile, using transaction: Any) {
|
||||
// let transaction = transaction as! YapDatabaseReadWriteTransaction
|
||||
// let profileManager = SSKEnvironment.shared.profileManager
|
||||
// if let displayName = profile.displayName {
|
||||
// profileManager.updateProfileForContact(withID: publicKey, displayName: displayName, with: transaction)
|
||||
// }
|
||||
// if let profileKey = profile.profileKey, let profilePictureURL = profile.profilePictureURL, profileKey.count == kAES256_KeyByteLength {
|
||||
// profileManager.setProfileKeyData(profileKey, forRecipientId: publicKey, avatarURL: profilePictureURL)
|
||||
// }
|
||||
let transaction = transaction as! YapDatabaseReadWriteTransaction
|
||||
let profileManager = SSKEnvironment.shared.profileManager
|
||||
if let displayName = profile.displayName {
|
||||
profileManager.updateProfileForContact(withID: publicKey, displayName: displayName, with: transaction)
|
||||
}
|
||||
if let profileKey = profile.profileKey, let profilePictureURL = profile.profilePictureURL, profileKey.count == kAES256_KeyByteLength {
|
||||
profileManager.setProfileKeyData(profileKey, forRecipientId: publicKey, avatarURL: profilePictureURL)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the ID of the thread the message was stored under along with the `TSIncomingMessage` that was constructed.
|
||||
public func persist(_ message: VisibleMessage, using transaction: Any) -> (String, Any) {
|
||||
let transaction = transaction as! YapDatabaseReadWriteTransaction
|
||||
let thread = TSContactThread.getOrCreateThread(withContactId: message.sender!, transaction: transaction)
|
||||
let message = TSIncomingMessage.from(message, using: transaction)
|
||||
let message = TSIncomingMessage.from(message, associatedWith: thread, using: transaction)
|
||||
message.save(with: transaction)
|
||||
return (thread.uniqueId!, message)
|
||||
}
|
||||
|
@ -230,7 +230,7 @@ extension Storage : SessionMessagingKitStorageProtocol {
|
|||
Storage.read { transaction in
|
||||
threadOrNil = TSContactThread.getWithContactId(senderPublicKey, transaction: transaction)
|
||||
}
|
||||
guard let thread = threadOrNil else { return } // Ignore if the thread doesn't exist yet
|
||||
guard let thread = threadOrNil else { return }
|
||||
func showTypingIndicatorsIfNeeded() {
|
||||
SSKEnvironment.shared.typingIndicators.didReceiveTypingStartedMessage(inThread: thread, recipientId: senderPublicKey, deviceId: 1)
|
||||
}
|
||||
|
@ -248,7 +248,7 @@ extension Storage : SessionMessagingKitStorageProtocol {
|
|||
Storage.read { transaction in
|
||||
threadOrNil = TSContactThread.getWithContactId(senderPublicKey, transaction: transaction)
|
||||
}
|
||||
guard let thread = threadOrNil else { return } // Ignore if the thread doesn't exist yet
|
||||
guard let thread = threadOrNil else { return }
|
||||
func hideTypingIndicatorsIfNeeded() {
|
||||
SSKEnvironment.shared.typingIndicators.didReceiveTypingStoppedMessage(inThread: thread, recipientId: senderPublicKey, deviceId: 1)
|
||||
}
|
||||
|
@ -266,7 +266,7 @@ extension Storage : SessionMessagingKitStorageProtocol {
|
|||
Storage.read { transaction in
|
||||
threadOrNil = TSContactThread.getWithContactId(senderPublicKey, transaction: transaction)
|
||||
}
|
||||
guard let thread = threadOrNil else { return } // Ignore if the thread doesn't exist yet
|
||||
guard let thread = threadOrNil else { return }
|
||||
func cancelTypingIndicatorsIfNeeded() {
|
||||
SSKEnvironment.shared.typingIndicators.didReceiveIncomingMessage(inThread: thread, recipientId: senderPublicKey, deviceId: 1)
|
||||
}
|
||||
|
@ -285,4 +285,40 @@ extension Storage : SessionMessagingKitStorageProtocol {
|
|||
SSKEnvironment.shared.notificationsManager!.notifyUser(for: (message as! TSIncomingMessage), in: thread, transaction: transaction)
|
||||
}
|
||||
}
|
||||
|
||||
public func markMessagesAsRead(_ timestamps: [UInt64], from senderPublicKey: String, at timestamp: UInt64) {
|
||||
SSKEnvironment.shared.readReceiptManager.processReadReceipts(fromRecipientId: senderPublicKey, sentTimestamps: timestamps.map { NSNumber(value: $0) }, readTimestamp: timestamp)
|
||||
}
|
||||
|
||||
public func setExpirationTimer(to duration: UInt32, for senderPublicKey: String, using transaction: Any) {
|
||||
let transaction = transaction as! YapDatabaseReadWriteTransaction
|
||||
var threadOrNil: TSContactThread?
|
||||
Storage.read { transaction in
|
||||
threadOrNil = TSContactThread.getWithContactId(senderPublicKey, transaction: transaction)
|
||||
}
|
||||
guard let thread = threadOrNil else { return }
|
||||
let configuration = OWSDisappearingMessagesConfiguration(threadId: thread.uniqueId!, enabled: true, durationSeconds: duration)
|
||||
configuration.save(with: transaction)
|
||||
let senderDisplayName = SSKEnvironment.shared.profileManager.profileNameForRecipient(withID: senderPublicKey, transaction: transaction)
|
||||
let message = OWSDisappearingConfigurationUpdateInfoMessage(timestamp: NSDate.millisecondTimestamp(), thread: thread,
|
||||
configuration: configuration, createdByRemoteName: senderDisplayName, createdInExistingGroup: false)
|
||||
message.save(with: transaction)
|
||||
SSKEnvironment.shared.disappearingMessagesJob.startIfNecessary()
|
||||
}
|
||||
|
||||
public func disableExpirationTimer(for senderPublicKey: String, using transaction: Any) {
|
||||
let transaction = transaction as! YapDatabaseReadWriteTransaction
|
||||
var threadOrNil: TSContactThread?
|
||||
Storage.read { transaction in
|
||||
threadOrNil = TSContactThread.getWithContactId(senderPublicKey, transaction: transaction)
|
||||
}
|
||||
guard let thread = threadOrNil else { return }
|
||||
let configuration = OWSDisappearingMessagesConfiguration(threadId: thread.uniqueId!, enabled: false, durationSeconds: 24 * 60 * 60)
|
||||
configuration.save(with: transaction)
|
||||
let senderDisplayName = SSKEnvironment.shared.profileManager.profileNameForRecipient(withID: senderPublicKey, transaction: transaction)
|
||||
let message = OWSDisappearingConfigurationUpdateInfoMessage(timestamp: NSDate.millisecondTimestamp(), thread: thread,
|
||||
configuration: configuration, createdByRemoteName: senderDisplayName, createdInExistingGroup: false)
|
||||
message.save(with: transaction)
|
||||
SSKEnvironment.shared.disappearingMessagesJob.startIfNecessary()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,4 +4,5 @@ public protocol JobDelegate {
|
|||
|
||||
func handleJobSucceeded(_ job: Job)
|
||||
func handleJobFailed(_ job: Job, with error: Error)
|
||||
func handleJobFailedPermanently(_ job: Job, with error: Error)
|
||||
}
|
||||
|
|
|
@ -47,6 +47,20 @@ public final class JobQueue : NSObject, JobDelegate {
|
|||
})
|
||||
}
|
||||
|
||||
public func handleJobFailedPermanently(_ job: Job, with error: Error) {
|
||||
job.failureCount += 1
|
||||
let storage = Configuration.shared.storage
|
||||
storage.withAsync({ transaction in
|
||||
storage.persist(job, using: transaction)
|
||||
}, completion: { // Intentionally capture self
|
||||
storage.withAsync({ transaction in
|
||||
storage.markJobAsFailed(job, using: transaction)
|
||||
}, completion: {
|
||||
// Do nothing
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
private func getRetryInterval(for job: Job) -> TimeInterval {
|
||||
// Arbitrary backoff factor...
|
||||
// try 1 delay: 0.00s
|
||||
|
|
|
@ -44,7 +44,11 @@ public final class MessageReceiveJob : NSObject, Job, NSCoding { // NSObject/NSC
|
|||
self.handleSuccess()
|
||||
} catch {
|
||||
SNLog("Couldn't parse message due to error: \(error).")
|
||||
self.handleFailure(error: error)
|
||||
if let error = error as? MessageReceiver.Error, !error.isRetryable {
|
||||
self.handlePermanentFailure(error: error)
|
||||
} else {
|
||||
self.handleFailure(error: error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}, completion: { })
|
||||
|
@ -54,6 +58,10 @@ public final class MessageReceiveJob : NSObject, Job, NSCoding { // NSObject/NSC
|
|||
delegate?.handleJobSucceeded(self)
|
||||
}
|
||||
|
||||
private func handlePermanentFailure(error: Error) {
|
||||
delegate?.handleJobFailedPermanently(self, with: error)
|
||||
}
|
||||
|
||||
private func handleFailure(error: Error) {
|
||||
delegate?.handleJobFailed(self, with: error)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
import SessionUtilitiesKit
|
||||
|
||||
// TODO:
|
||||
// • Threads don't show up on the first message; only on the second.
|
||||
// • Profile pictures aren't showing up.
|
||||
|
||||
internal enum MessageReceiver {
|
||||
|
||||
internal enum Error : LocalizedError {
|
||||
|
@ -15,6 +19,13 @@ internal enum MessageReceiver {
|
|||
case sharedSecretGenerationFailed
|
||||
case selfSend
|
||||
|
||||
internal var isRetryable: Bool {
|
||||
switch self {
|
||||
case .invalidMessage, .unknownMessage, .unknownEnvelopeType, .noData, .senderBlocked, .selfSend: return false
|
||||
default: return true
|
||||
}
|
||||
}
|
||||
|
||||
internal var errorDescription: String? {
|
||||
switch self {
|
||||
case .invalidMessage: return "Invalid message."
|
||||
|
@ -57,6 +68,7 @@ internal enum MessageReceiver {
|
|||
let message: Message? = {
|
||||
if let readReceipt = ReadReceipt.fromProto(proto) { return readReceipt }
|
||||
if let sessionRequest = SessionRequest.fromProto(proto) { return sessionRequest }
|
||||
if let nullMessage = NullMessage.fromProto(proto) { return nullMessage }
|
||||
if let typingIndicator = TypingIndicator.fromProto(proto) { return typingIndicator }
|
||||
if let closedGroupUpdate = ClosedGroupUpdate.fromProto(proto) { return closedGroupUpdate }
|
||||
if let expirationTimerUpdate = ExpirationTimerUpdate.fromProto(proto) { return expirationTimerUpdate }
|
||||
|
@ -78,6 +90,7 @@ internal enum MessageReceiver {
|
|||
switch message {
|
||||
case let message as ReadReceipt: handleReadReceipt(message, using: transaction)
|
||||
case let message as SessionRequest: handleSessionRequest(message, using: transaction)
|
||||
case let message as NullMessage: handleNullMessage(message, using: transaction)
|
||||
case let message as TypingIndicator: handleTypingIndicator(message, using: transaction)
|
||||
case let message as ClosedGroupUpdate: handleClosedGroupUpdate(message, using: transaction)
|
||||
case let message as ExpirationTimerUpdate: handleExpirationTimerUpdate(message, using: transaction)
|
||||
|
@ -87,11 +100,15 @@ internal enum MessageReceiver {
|
|||
}
|
||||
|
||||
private static func handleReadReceipt(_ message: ReadReceipt, using transaction: Any) {
|
||||
|
||||
Configuration.shared.storage.markMessagesAsRead(message.timestamps!, from: message.sender!, at: message.receivedTimestamp!)
|
||||
}
|
||||
|
||||
private static func handleSessionRequest(_ message: SessionRequest, using transaction: Any) {
|
||||
// TODO: Implement
|
||||
}
|
||||
|
||||
private static func handleNullMessage(_ message: NullMessage, using transaction: Any) {
|
||||
// TODO: Implement
|
||||
}
|
||||
|
||||
private static func handleTypingIndicator(_ message: TypingIndicator, using transaction: Any) {
|
||||
|
@ -107,7 +124,12 @@ internal enum MessageReceiver {
|
|||
}
|
||||
|
||||
private static func handleExpirationTimerUpdate(_ message: ExpirationTimerUpdate, using transaction: Any) {
|
||||
|
||||
let storage = Configuration.shared.storage
|
||||
if message.duration! > 0 {
|
||||
storage.setExpirationTimer(to: message.duration!, for: message.sender!, using: transaction)
|
||||
} else {
|
||||
storage.disableExpirationTimer(for: message.sender!, using: transaction)
|
||||
}
|
||||
}
|
||||
|
||||
private static func handleVisibleMessage(_ message: VisibleMessage, using transaction: Any) {
|
||||
|
|
|
@ -70,4 +70,7 @@ public protocol SessionMessagingKitStorageProtocol {
|
|||
func hideTypingIndicatorIfNeeded(for senderPublicKey: String)
|
||||
func cancelTypingIndicatorsIfNeeded(for senderPublicKey: String)
|
||||
func notifyUserIfNeeded(for message: Any, threadID: String)
|
||||
func markMessagesAsRead(_ timestamps: [UInt64], from senderPublicKey: String, at timestamp: UInt64)
|
||||
func setExpirationTimer(to duration: UInt32, for senderPublicKey: String, using transaction: Any)
|
||||
func disableExpirationTimer(for senderPublicKey: String, using transaction: Any)
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ FOUNDATION_EXPORT const unsigned char SignalUtilitiesKitVersionString[];
|
|||
#import <SignalUtilitiesKit/OWSBackgroundTask.h>
|
||||
#import <SignalUtilitiesKit/OWSBackupFragment.h>
|
||||
#import <SignalUtilitiesKit/OWSBlockingManager.h>
|
||||
#import <SignalUtilitiesKit/OWSDisappearingConfigurationUpdateInfoMessage.h>
|
||||
#import <SignalUtilitiesKit/OWSDisappearingMessagesConfiguration.h>
|
||||
#import <SignalUtilitiesKit/OWSDisappearingMessagesJob.h>
|
||||
#import <SignalUtilitiesKit/OWSDispatch.h>
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
|
||||
public extension TSIncomingMessage {
|
||||
|
||||
static func from(_ visibleMessage: VisibleMessage, using transaction: YapDatabaseReadWriteTransaction) -> TSIncomingMessage {
|
||||
static func from(_ visibleMessage: VisibleMessage, associatedWith thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) -> TSIncomingMessage {
|
||||
let sender = visibleMessage.sender!
|
||||
let thread = TSContactThread.getOrCreateThread(withContactId: sender, transaction: transaction)
|
||||
return TSIncomingMessage(
|
||||
timestamp: visibleMessage.receivedTimestamp!,
|
||||
in: thread,
|
||||
|
|
Loading…
Reference in New Issue