Merge pull request #356 from oxen-io/multi-device

Sync Expiration Timer Updates
pull/359/head
Niels Andriesse 4 years ago committed by GitHub
commit 220486441d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -2,13 +2,20 @@ import SessionUtilitiesKit
@objc(SNExpirationTimerUpdate) @objc(SNExpirationTimerUpdate)
public final class ExpirationTimerUpdate : ControlMessage { public final class ExpirationTimerUpdate : ControlMessage {
/// In the case of a sync message, the public key of the person the message was targeted at.
///
/// - Note: `nil` if this isn't a sync message.
public var syncTarget: String?
public var duration: UInt32? public var duration: UInt32?
public override var isSelfSendValid: Bool { true }
// MARK: Initialization // MARK: Initialization
public override init() { super.init() } public override init() { super.init() }
internal init(duration: UInt32) { internal init(syncTarget: String?, duration: UInt32) {
super.init() super.init()
self.syncTarget = syncTarget
self.duration = duration self.duration = duration
} }
@ -21,11 +28,13 @@ public final class ExpirationTimerUpdate : ControlMessage {
// MARK: Coding // MARK: Coding
public required init?(coder: NSCoder) { public required init?(coder: NSCoder) {
super.init(coder: coder) super.init(coder: coder)
if let syncTarget = coder.decodeObject(forKey: "syncTarget") as! String? { self.syncTarget = syncTarget }
if let duration = coder.decodeObject(forKey: "durationSeconds") as! UInt32? { self.duration = duration } if let duration = coder.decodeObject(forKey: "durationSeconds") as! UInt32? { self.duration = duration }
} }
public override func encode(with coder: NSCoder) { public override func encode(with coder: NSCoder) {
super.encode(with: coder) super.encode(with: coder)
coder.encode(syncTarget, forKey: "syncTarget")
coder.encode(duration, forKey: "durationSeconds") coder.encode(duration, forKey: "durationSeconds")
} }
@ -34,8 +43,9 @@ public final class ExpirationTimerUpdate : ControlMessage {
guard let dataMessageProto = proto.dataMessage else { return nil } guard let dataMessageProto = proto.dataMessage else { return nil }
let isExpirationTimerUpdate = (dataMessageProto.flags & UInt32(SNProtoDataMessage.SNProtoDataMessageFlags.expirationTimerUpdate.rawValue)) != 0 let isExpirationTimerUpdate = (dataMessageProto.flags & UInt32(SNProtoDataMessage.SNProtoDataMessageFlags.expirationTimerUpdate.rawValue)) != 0
guard isExpirationTimerUpdate else { return nil } guard isExpirationTimerUpdate else { return nil }
let syncTarget = dataMessageProto.syncTarget
let duration = dataMessageProto.expireTimer let duration = dataMessageProto.expireTimer
return ExpirationTimerUpdate(duration: duration) return ExpirationTimerUpdate(syncTarget: syncTarget, duration: duration)
} }
public override func toProto(using transaction: YapDatabaseReadWriteTransaction) -> SNProtoContent? { public override func toProto(using transaction: YapDatabaseReadWriteTransaction) -> SNProtoContent? {
@ -46,6 +56,7 @@ public final class ExpirationTimerUpdate : ControlMessage {
let dataMessageProto = SNProtoDataMessage.builder() let dataMessageProto = SNProtoDataMessage.builder()
dataMessageProto.setFlags(UInt32(SNProtoDataMessage.SNProtoDataMessageFlags.expirationTimerUpdate.rawValue)) dataMessageProto.setFlags(UInt32(SNProtoDataMessage.SNProtoDataMessageFlags.expirationTimerUpdate.rawValue))
dataMessageProto.setExpireTimer(duration) dataMessageProto.setExpireTimer(duration)
if let syncTarget = syncTarget { dataMessageProto.setSyncTarget(syncTarget) }
// Group context // Group context
do { do {
try setGroupContextIfNeeded(on: dataMessageProto, using: transaction) try setGroupContextIfNeeded(on: dataMessageProto, using: transaction)
@ -67,6 +78,7 @@ public final class ExpirationTimerUpdate : ControlMessage {
public override var description: String { public override var description: String {
""" """
ExpirationTimerUpdate( ExpirationTimerUpdate(
syncTarget: \(syncTarget ?? "null")
duration: \(duration?.description ?? "null") duration: \(duration?.description ?? "null")
) )
""" """

@ -96,13 +96,13 @@ extension MessageReceiver {
private static func handleExpirationTimerUpdate(_ message: ExpirationTimerUpdate, using transaction: Any) { private static func handleExpirationTimerUpdate(_ message: ExpirationTimerUpdate, using transaction: Any) {
if message.duration! > 0 { if message.duration! > 0 {
setExpirationTimer(to: message.duration!, for: message.sender!, groupPublicKey: message.groupPublicKey, using: transaction) setExpirationTimer(to: message.duration!, for: message.sender!, syncTarget: message.syncTarget, groupPublicKey: message.groupPublicKey, using: transaction)
} else { } else {
disableExpirationTimer(for: message.sender!, groupPublicKey: message.groupPublicKey, using: transaction) disableExpirationTimer(for: message.sender!, syncTarget: message.syncTarget, groupPublicKey: message.groupPublicKey, using: transaction)
} }
} }
public static func setExpirationTimer(to duration: UInt32, for senderPublicKey: String, groupPublicKey: String?, using transaction: Any) { public static func setExpirationTimer(to duration: UInt32, for senderPublicKey: String, syncTarget: String?, groupPublicKey: String?, using transaction: Any) {
let transaction = transaction as! YapDatabaseReadWriteTransaction let transaction = transaction as! YapDatabaseReadWriteTransaction
var threadOrNil: TSThread? var threadOrNil: TSThread?
if let groupPublicKey = groupPublicKey { if let groupPublicKey = groupPublicKey {
@ -110,7 +110,7 @@ extension MessageReceiver {
let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey)
threadOrNil = TSGroupThread.fetch(uniqueId: TSGroupThread.threadId(fromGroupId: groupID), transaction: transaction) threadOrNil = TSGroupThread.fetch(uniqueId: TSGroupThread.threadId(fromGroupId: groupID), transaction: transaction)
} else { } else {
threadOrNil = TSContactThread.getWithContactId(senderPublicKey, transaction: transaction) threadOrNil = TSContactThread.getWithContactId(syncTarget ?? senderPublicKey, transaction: transaction)
} }
guard let thread = threadOrNil else { return } guard let thread = threadOrNil else { return }
let configuration = OWSDisappearingMessagesConfiguration(threadId: thread.uniqueId!, enabled: true, durationSeconds: duration) let configuration = OWSDisappearingMessagesConfiguration(threadId: thread.uniqueId!, enabled: true, durationSeconds: duration)
@ -122,7 +122,7 @@ extension MessageReceiver {
SSKEnvironment.shared.disappearingMessagesJob.startIfNecessary() SSKEnvironment.shared.disappearingMessagesJob.startIfNecessary()
} }
public static func disableExpirationTimer(for senderPublicKey: String, groupPublicKey: String?, using transaction: Any) { public static func disableExpirationTimer(for senderPublicKey: String, syncTarget: String?, groupPublicKey: String?, using transaction: Any) {
let transaction = transaction as! YapDatabaseReadWriteTransaction let transaction = transaction as! YapDatabaseReadWriteTransaction
var threadOrNil: TSThread? var threadOrNil: TSThread?
if let groupPublicKey = groupPublicKey { if let groupPublicKey = groupPublicKey {
@ -130,7 +130,7 @@ extension MessageReceiver {
let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey) let groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(groupPublicKey)
threadOrNil = TSGroupThread.fetch(uniqueId: TSGroupThread.threadId(fromGroupId: groupID), transaction: transaction) threadOrNil = TSGroupThread.fetch(uniqueId: TSGroupThread.threadId(fromGroupId: groupID), transaction: transaction)
} else { } else {
threadOrNil = TSContactThread.getWithContactId(senderPublicKey, transaction: transaction) threadOrNil = TSContactThread.getWithContactId(syncTarget ?? senderPublicKey, transaction: transaction)
} }
guard let thread = threadOrNil else { return } guard let thread = threadOrNil else { return }
let configuration = OWSDisappearingMessagesConfiguration(threadId: thread.uniqueId!, enabled: false, durationSeconds: 24 * 60 * 60) let configuration = OWSDisappearingMessagesConfiguration(threadId: thread.uniqueId!, enabled: false, durationSeconds: 24 * 60 * 60)

@ -346,33 +346,36 @@ public final class MessageSender : NSObject {
public static func handleSuccessfulMessageSend(_ message: Message, to destination: Message.Destination, isSyncMessage: Bool = false, using transaction: Any) { public static func handleSuccessfulMessageSend(_ message: Message, to destination: Message.Destination, isSyncMessage: Bool = false, using transaction: Any) {
let storage = SNMessagingKitConfiguration.shared.storage let storage = SNMessagingKitConfiguration.shared.storage
let transaction = transaction as! YapDatabaseReadWriteTransaction let transaction = transaction as! YapDatabaseReadWriteTransaction
guard let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) else { return }
// Ignore future self-sends // Ignore future self-sends
Storage.shared.addReceivedMessageTimestamp(message.sentTimestamp!, using: transaction) Storage.shared.addReceivedMessageTimestamp(message.sentTimestamp!, using: transaction)
// Track the open group server message ID // Get the visible message if possible
tsMessage.openGroupServerMessageID = message.openGroupServerMessageID ?? 0 if let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) {
tsMessage.save(with: transaction) // Track the open group server message ID
if let serverID = message.openGroupServerMessageID { tsMessage.openGroupServerMessageID = message.openGroupServerMessageID ?? 0
storage.setIDForMessage(withServerID: serverID, to: tsMessage.uniqueId!, using: transaction) tsMessage.save(with: transaction)
} if let serverID = message.openGroupServerMessageID {
// Mark the message as sent storage.setIDForMessage(withServerID: serverID, to: tsMessage.uniqueId!, using: transaction)
var recipients = [ message.recipient! ] }
if case .closedGroup(_) = destination, let threadID = message.threadID, // threadID should always be set at this point // Mark the message as sent
let thread = TSGroupThread.fetch(uniqueId: threadID, transaction: transaction), thread.isClosedGroup { var recipients = [ message.recipient! ]
recipients = thread.groupModel.groupMemberIds if case .closedGroup(_) = destination, let threadID = message.threadID, // threadID should always be set at this point
} let thread = TSGroupThread.fetch(uniqueId: threadID, transaction: transaction), thread.isClosedGroup {
recipients.forEach { recipient in recipients = thread.groupModel.groupMemberIds
tsMessage.update(withSentRecipient: recipient, wasSentByUD: true, transaction: transaction) }
recipients.forEach { recipient in
tsMessage.update(withSentRecipient: recipient, wasSentByUD: true, transaction: transaction)
}
// Start the disappearing messages timer if needed
OWSDisappearingMessagesJob.shared().startAnyExpiration(for: tsMessage, expirationStartedAt: NSDate.millisecondTimestamp(), transaction: transaction)
} }
// Start the disappearing messages timer if needed
OWSDisappearingMessagesJob.shared().startAnyExpiration(for: tsMessage, expirationStartedAt: NSDate.millisecondTimestamp(), transaction: transaction)
// Sync the message if: // Sync the message if:
// it's a visible message // it's a visible message or an expiration timer update
// the destination was a contact // the destination was a contact
// we didn't sync it already // we didn't sync it already
let userPublicKey = getUserHexEncodedPublicKey() let userPublicKey = getUserHexEncodedPublicKey()
if case .contact(let publicKey) = destination, !isSyncMessage, let message = message as? VisibleMessage { if case .contact(let publicKey) = destination, !isSyncMessage {
message.syncTarget = publicKey if let message = message as? VisibleMessage { message.syncTarget = publicKey }
if let message = message as? ExpirationTimerUpdate { message.syncTarget = publicKey }
// FIXME: Make this a job // FIXME: Make this a job
sendToSnodeDestination(.contact(publicKey: userPublicKey), message: message, using: transaction, isSyncMessage: true).retainUntilComplete() sendToSnodeDestination(.contact(publicKey: userPublicKey), message: message, using: transaction, isSyncMessage: true).retainUntilComplete()
} }

Loading…
Cancel
Save