Fix duplicate messages & debug
This commit is contained in:
parent
e3304a40f9
commit
addc859c84
|
@ -377,7 +377,6 @@ class MediaGallery: NSObject, MediaGalleryDataSource, MediaTileViewControllerDel
|
|||
}
|
||||
|
||||
guard let initialDetailItem = galleryItem else {
|
||||
owsFailDebug("unexpectedly failed to build initialDetailItem.")
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -61,5 +61,26 @@ extension Storage {
|
|||
guard let tsIncomingMessage = TSIncomingMessage.fetch(uniqueId: tsIncomingMessageID, transaction: transaction) else { return }
|
||||
tsIncomingMessage.touch(with: transaction)
|
||||
}
|
||||
|
||||
private static let receivedMessageTimestampsCollection = "ReceivedMessageTimestampsCollection"
|
||||
|
||||
public func getReceivedMessageTimestamps(using transaction: Any) -> [UInt64] {
|
||||
var result: [UInt64] = []
|
||||
let transaction = transaction as! YapDatabaseReadWriteTransaction
|
||||
transaction.enumerateRows(inCollection: Storage.receivedMessageTimestampsCollection) { _, object, _, _ in
|
||||
guard let timestamp = object as? UInt64 else { return }
|
||||
result.append(timestamp)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
public func addReceivedMessageTimestamp(_ timestamp: UInt64, using transaction: Any) {
|
||||
var receivedMessageTimestamps = getReceivedMessageTimestamps(using: transaction)
|
||||
// TODO: Do we need to sort the timestamps here?
|
||||
if receivedMessageTimestamps.count > 1000 { receivedMessageTimestamps.remove(at: 0) } // Limit the size of the collection to 1000
|
||||
receivedMessageTimestamps.append(timestamp)
|
||||
let transaction = transaction as! YapDatabaseReadWriteTransaction
|
||||
transaction.setObject(receivedMessageTimestamps, forKey: "receivedMessageTimestamps", inCollection: Storage.receivedMessageTimestampsCollection)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -78,7 +78,6 @@ public final class MessageSendJob : NSObject, Job, NSCoding { // NSObject/NSCodi
|
|||
}
|
||||
if !attachmentsToUpload.isEmpty { return } // Wait for all attachments to upload before continuing
|
||||
}
|
||||
// FIXME: This doesn't yet handle the attachment side of link previews, quotes, etc.
|
||||
storage.withAsync({ transaction in // Intentionally capture self
|
||||
MessageSender.send(self.message, to: self.destination, using: transaction).done(on: DispatchQueue.global(qos: .userInitiated)) {
|
||||
self.handleSuccess()
|
||||
|
|
|
@ -46,12 +46,12 @@ public extension VisibleMessage {
|
|||
}
|
||||
|
||||
public func toProto(using transaction: YapDatabaseReadWriteTransaction) -> SNProtoDataMessageQuote? {
|
||||
guard let timestamp = timestamp, let publicKey = publicKey, let text = text else {
|
||||
guard let timestamp = timestamp, let publicKey = publicKey else {
|
||||
SNLog("Couldn't construct quote proto from: \(self).")
|
||||
return nil
|
||||
}
|
||||
let quoteProto = SNProtoDataMessageQuote.builder(id: timestamp, author: publicKey)
|
||||
quoteProto.setText(text)
|
||||
if let text = text { quoteProto.setText(text) }
|
||||
addAttachmentsIfNeeded(to: quoteProto, using: transaction)
|
||||
do {
|
||||
return try quoteProto.build()
|
||||
|
|
|
@ -25,12 +25,20 @@ public final class VisibleMessage : Message {
|
|||
super.init(coder: coder)
|
||||
if let text = coder.decodeObject(forKey: "body") as! String? { self.text = text }
|
||||
if let attachmentIDs = coder.decodeObject(forKey: "attachments") as! [String]? { self.attachmentIDs = attachmentIDs }
|
||||
if let quote = coder.decodeObject(forKey: "quote") as! Quote? { self.quote = quote }
|
||||
if let linkPreview = coder.decodeObject(forKey: "linkPreview") as! LinkPreview? { self.linkPreview = linkPreview }
|
||||
// TODO: Contact
|
||||
if let profile = coder.decodeObject(forKey: "profile") as! Profile? { self.profile = profile }
|
||||
}
|
||||
|
||||
public override func encode(with coder: NSCoder) {
|
||||
super.encode(with: coder)
|
||||
coder.encode(text, forKey: "body")
|
||||
coder.encode(attachmentIDs, forKey: "attachments")
|
||||
coder.encode(quote, forKey: "quote")
|
||||
coder.encode(linkPreview, forKey: "linkPreview")
|
||||
// TODO: Contact
|
||||
coder.encode(profile, forKey: "profile")
|
||||
}
|
||||
|
||||
// MARK: Proto Conversion
|
||||
|
|
|
@ -160,14 +160,23 @@ extension MessageReceiver {
|
|||
// Persist the message
|
||||
guard let (threadID, tsIncomingMessageID) = storage.persist(message, groupPublicKey: message.groupPublicKey, using: transaction) else { throw Error.noThread }
|
||||
message.threadID = threadID
|
||||
// Handle quoted attachment if needed
|
||||
if message.quote != nil && proto.dataMessage?.quote != nil, let thread = TSThread.fetch(uniqueId: threadID, transaction: transaction) {
|
||||
let tsQuote = TSQuotedMessage(for: proto.dataMessage!, thread: thread, transaction: transaction)
|
||||
if let thumbnailID = tsQuote?.thumbnailAttachmentStreamId() ?? tsQuote?.thumbnailAttachmentPointerId() {
|
||||
message.quote?.attachmentID = thumbnailID
|
||||
}
|
||||
}
|
||||
// Start attachment downloads if needed
|
||||
storage.withAsync({ transaction in
|
||||
attachmentIDs.forEach { attachmentID in
|
||||
let downloadJob = AttachmentDownloadJob(attachmentID: attachmentID, tsIncomingMessageID: tsIncomingMessageID)
|
||||
if CurrentAppContext().isMainAppAndActive {
|
||||
JobQueue.shared.add(downloadJob, using: transaction)
|
||||
} else {
|
||||
JobQueue.shared.addWithoutExecuting(downloadJob, using: transaction)
|
||||
DispatchQueue.main.async {
|
||||
attachmentIDs.forEach { attachmentID in
|
||||
let downloadJob = AttachmentDownloadJob(attachmentID: attachmentID, tsIncomingMessageID: tsIncomingMessageID)
|
||||
if CurrentAppContext().isMainAppAndActive { // This has to be called from the main thread
|
||||
JobQueue.shared.add(downloadJob, using: transaction)
|
||||
} else {
|
||||
JobQueue.shared.addWithoutExecuting(downloadJob, using: transaction)
|
||||
}
|
||||
}
|
||||
}
|
||||
}, completion: { })
|
||||
|
|
|
@ -3,6 +3,7 @@ import SessionUtilitiesKit
|
|||
internal enum MessageReceiver {
|
||||
|
||||
internal enum Error : LocalizedError {
|
||||
case duplicateMessage
|
||||
case invalidMessage
|
||||
case unknownMessage
|
||||
case unknownEnvelopeType
|
||||
|
@ -18,13 +19,14 @@ internal enum MessageReceiver {
|
|||
|
||||
internal var isRetryable: Bool {
|
||||
switch self {
|
||||
case .invalidMessage, .unknownMessage, .unknownEnvelopeType, .noData, .senderBlocked, .selfSend: return false
|
||||
case .duplicateMessage, .invalidMessage, .unknownMessage, .unknownEnvelopeType, .noData, .senderBlocked, .selfSend: return false
|
||||
default: return true
|
||||
}
|
||||
}
|
||||
|
||||
internal var errorDescription: String? {
|
||||
switch self {
|
||||
case .duplicateMessage: return "Duplicate message."
|
||||
case .invalidMessage: return "Invalid message."
|
||||
case .unknownMessage: return "Unknown message type."
|
||||
case .unknownEnvelopeType: return "Unknown envelope type."
|
||||
|
@ -45,6 +47,9 @@ internal enum MessageReceiver {
|
|||
let userPublicKey = Configuration.shared.storage.getUserPublicKey()
|
||||
// Parse the envelope
|
||||
let envelope = try SNProtoEnvelope.parseData(data)
|
||||
let storage = Configuration.shared.storage
|
||||
guard !Set(storage.getReceivedMessageTimestamps(using: transaction)).contains(envelope.timestamp) else { throw Error.duplicateMessage }
|
||||
storage.addReceivedMessageTimestamp(envelope.timestamp, using: transaction)
|
||||
// Decrypt the contents
|
||||
let plaintext: Data
|
||||
let sender: String
|
||||
|
|
|
@ -71,6 +71,8 @@ public protocol SessionMessagingKitStorageProtocol {
|
|||
|
||||
// MARK: - Message Handling
|
||||
|
||||
func getReceivedMessageTimestamps(using transaction: Any) -> [UInt64]
|
||||
func addReceivedMessageTimestamp(_ timestamp: UInt64, using transaction: Any)
|
||||
/// Returns the ID of the thread the message was stored under along with the ID of the `TSIncomingMessage` that was constructed.
|
||||
func persist(_ message: VisibleMessage, groupPublicKey: String?, using transaction: Any) -> (String, String)?
|
||||
/// Returns the IDs of the saved attachments.
|
||||
|
|
|
@ -20,16 +20,14 @@ extension MessageSender : SharedSenderKeysDelegate {
|
|||
streams.append(stream)
|
||||
stream.write($0.dataSource)
|
||||
stream.save(with: transaction)
|
||||
tsMessage.attachmentIds.add(stream.uniqueId!)
|
||||
}
|
||||
if let quotedMessageThumbnails = tsMessage.quotedMessage?.createThumbnailAttachmentsIfNecessary(with: transaction) {
|
||||
streams += quotedMessageThumbnails
|
||||
}
|
||||
tsMessage.quotedMessage?.createThumbnailAttachmentsIfNecessary(with: transaction)
|
||||
if let linkPreviewAttachmentID = tsMessage.linkPreview?.imageAttachmentId,
|
||||
let stream = TSAttachment.fetch(uniqueId: linkPreviewAttachmentID, transaction: transaction) as? TSAttachmentStream {
|
||||
streams.append(stream)
|
||||
}
|
||||
message.attachmentIDs = streams.map { $0.uniqueId! }
|
||||
tsMessage.attachmentIds.addObjects(from: message.attachmentIDs)
|
||||
tsMessage.save(with: transaction)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue