From f9c2a2ce99b174fac0eef5cea6e2713f920827af Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Thu, 25 Aug 2022 11:12:22 +1000 Subject: [PATCH 1/7] tweak: fix an issue where we may delete the wrong open group message and update reactions to wrong open group messages in other threads with the same server id --- SessionMessagingKit/Open Groups/OpenGroupManager.swift | 2 ++ SessionMessagingKit/Sending & Receiving/MessageReceiver.swift | 2 ++ 2 files changed, 4 insertions(+) diff --git a/SessionMessagingKit/Open Groups/OpenGroupManager.swift b/SessionMessagingKit/Open Groups/OpenGroupManager.swift index 0f532bb9b..33fee96cc 100644 --- a/SessionMessagingKit/Open Groups/OpenGroupManager.swift +++ b/SessionMessagingKit/Open Groups/OpenGroupManager.swift @@ -594,6 +594,7 @@ public final class OpenGroupManager: NSObject { try MessageReceiver.handleOpenGroupReactions( db, + threadId: openGroup.threadId, openGroupMessageServerId: message.id, openGroupReactions: reactions ) @@ -608,6 +609,7 @@ public final class OpenGroupManager: NSObject { guard !messageServerIdsToRemove.isEmpty else { return } _ = try? Interaction + .filter(Interaction.Columns.threadId == openGroup.threadId) .filter(messageServerIdsToRemove.contains(Interaction.Columns.openGroupServerMessageId)) .deleteAll(db) } diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift index 20141c74b..2e427fda1 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift @@ -249,11 +249,13 @@ public enum MessageReceiver { public static func handleOpenGroupReactions( _ db: Database, + threadId: String, openGroupMessageServerId: Int64, openGroupReactions: [Reaction] ) throws { guard let interactionId: Int64 = try? Interaction .select(.id) + .filter(Interaction.Columns.threadId == threadId) .filter(Interaction.Columns.openGroupServerMessageId == openGroupMessageServerId) .asRequest(of: Int64.self) .fetchOne(db) From 128ef747b33aefd7ecb5b010709f6f8759c2576b Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Thu, 25 Aug 2022 11:51:53 +1000 Subject: [PATCH 2/7] tweak: only fetch and show 5 reactors for open group reactions --- SessionMessagingKit/Messages/Message.swift | 3 +++ SessionMessagingKit/Open Groups/OpenGroupAPI.swift | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/SessionMessagingKit/Messages/Message.swift b/SessionMessagingKit/Messages/Message.swift index 9dec50347..f37f93f10 100644 --- a/SessionMessagingKit/Messages/Message.swift +++ b/SessionMessagingKit/Messages/Message.swift @@ -369,8 +369,11 @@ public extension Message { let reactors = rawReaction.reactors { let timestampMs: Int64 = Int64(floor((Date().timeIntervalSince1970 * 1000))) + let maxLength: Int = !rawReaction.you || reactors.contains(userPublicKey) ? 5 : 4 let desiredReactorIds: [String] = reactors .filter { $0 != blindedUserPublicKey } + .prefix(maxLength) + .map{ $0 } results = results .appending( // Add the first reaction (with the count) diff --git a/SessionMessagingKit/Open Groups/OpenGroupAPI.swift b/SessionMessagingKit/Open Groups/OpenGroupAPI.swift index bcef9def5..e27f93428 100644 --- a/SessionMessagingKit/Open Groups/OpenGroupAPI.swift +++ b/SessionMessagingKit/Open Groups/OpenGroupAPI.swift @@ -99,7 +99,7 @@ public enum OpenGroupAPI { ), queryParameters: [ .updateTypes: UpdateTypes.reaction.rawValue, - .reactors: "20" + .reactors: "5" ] ), responseType: [Failable].self From 3a81ffc752c835f483ef59868f271c35296b1a04 Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Thu, 25 Aug 2022 12:01:49 +1000 Subject: [PATCH 3/7] feat: add response for reaction endpoints --- Session.xcodeproj/project.pbxproj | 4 ++ .../Open Groups/Models/ReactionResponse.swift | 44 +++++++++++++++++++ .../Open Groups/OpenGroupAPI.swift | 18 ++++++-- 3 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 SessionMessagingKit/Open Groups/Models/ReactionResponse.swift diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index bfb2637c1..15c1cea40 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -138,6 +138,7 @@ 7B7CB192271508AD0079FF93 /* CallRingTonePlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B7CB191271508AD0079FF93 /* CallRingTonePlayer.swift */; }; 7B81682328A4C1210069F315 /* UpdateTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B81682228A4C1210069F315 /* UpdateTypes.swift */; }; 7B81682828B310D50069F315 /* _007_HomeQueryOptimisationIndexes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B81682728B310D50069F315 /* _007_HomeQueryOptimisationIndexes.swift */; }; + 7B81682A28B6F1420069F315 /* ReactionResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B81682928B6F1420069F315 /* ReactionResponse.swift */; }; 7B8D5FC428332600008324D9 /* VisibleMessage+Reaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B8D5FC328332600008324D9 /* VisibleMessage+Reaction.swift */; }; 7B93D06A27CF173D00811CB6 /* MessageRequestsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B93D06927CF173D00811CB6 /* MessageRequestsViewController.swift */; }; 7B93D07027CF194000811CB6 /* ConfigurationMessage+Convenience.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B93D06E27CF194000811CB6 /* ConfigurationMessage+Convenience.swift */; }; @@ -1178,6 +1179,7 @@ 7B7CB191271508AD0079FF93 /* CallRingTonePlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallRingTonePlayer.swift; sourceTree = ""; }; 7B81682228A4C1210069F315 /* UpdateTypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateTypes.swift; sourceTree = ""; }; 7B81682728B310D50069F315 /* _007_HomeQueryOptimisationIndexes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = _007_HomeQueryOptimisationIndexes.swift; sourceTree = ""; }; + 7B81682928B6F1420069F315 /* ReactionResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionResponse.swift; sourceTree = ""; }; 7B8D5FC328332600008324D9 /* VisibleMessage+Reaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VisibleMessage+Reaction.swift"; sourceTree = ""; }; 7B93D06927CF173D00811CB6 /* MessageRequestsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageRequestsViewController.swift; sourceTree = ""; }; 7B93D06E27CF194000811CB6 /* ConfigurationMessage+Convenience.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ConfigurationMessage+Convenience.swift"; sourceTree = ""; }; @@ -3853,6 +3855,7 @@ FDC438A327BB107F00C60D73 /* UserBanRequest.swift */, FDC438A527BB113A00C60D73 /* UserUnbanRequest.swift */, FDC438A927BB12BB00C60D73 /* UserModeratorRequest.swift */, + 7B81682928B6F1420069F315 /* ReactionResponse.swift */, ); path = Models; sourceTree = ""; @@ -5203,6 +5206,7 @@ FD6A7A6B2818C17C00035AC1 /* UpdateProfilePictureJob.swift in Sources */, FD716E6A2850327900C96BF4 /* EndCallMode.swift in Sources */, FDF0B75C2807F41D004C14C5 /* MessageSender+Convenience.swift in Sources */, + 7B81682A28B6F1420069F315 /* ReactionResponse.swift in Sources */, FD09799727FFA84A00936362 /* RecipientState.swift in Sources */, FDA8EB00280E8D58002B68E5 /* FailedAttachmentDownloadsJob.swift in Sources */, FD09798927FD1C5A00936362 /* OpenGroup.swift in Sources */, diff --git a/SessionMessagingKit/Open Groups/Models/ReactionResponse.swift b/SessionMessagingKit/Open Groups/Models/ReactionResponse.swift new file mode 100644 index 000000000..51df94e20 --- /dev/null +++ b/SessionMessagingKit/Open Groups/Models/ReactionResponse.swift @@ -0,0 +1,44 @@ +// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. + +import Foundation + +extension OpenGroupAPI { + public struct ReactionAddResponse: Codable, Equatable { + enum CodingKeys: String, CodingKey { + case added + case seqNo = "seqno" + } + + /// This field indicates whether the reaction was added (true) or already present (false). + public let added: Bool + + /// The seqNo after the reaction is added. + public let seqNo: Int64 + } + + public struct ReactionRemoveResponse: Codable, Equatable { + enum CodingKeys: String, CodingKey { + case removed + case seqNo = "seqno" + } + + /// This field indicates whether the reaction was removed (true) or was not present to begin with (false). + public let removed: Bool + + /// The seqNo after the reaction is removed. + public let seqNo: Int64 + } + + public struct ReactionRemoveAllResponse: Codable, Equatable { + enum CodingKeys: String, CodingKey { + case removed + case seqNo = "seqno" + } + + /// This field shows the total number of reactions that were deleted. + public let removed: Int64 + + /// The seqNo after the reactions is all removed. + public let seqNo: Int64 + } +} diff --git a/SessionMessagingKit/Open Groups/OpenGroupAPI.swift b/SessionMessagingKit/Open Groups/OpenGroupAPI.swift index e27f93428..01ceb20fc 100644 --- a/SessionMessagingKit/Open Groups/OpenGroupAPI.swift +++ b/SessionMessagingKit/Open Groups/OpenGroupAPI.swift @@ -718,7 +718,11 @@ public enum OpenGroupAPI { ), using: dependencies ) - .map { responseInfo, _ in responseInfo } + .decoded(as: ReactionAddResponse.self, on: OpenGroupAPI.workQueue, using: dependencies) + .map { responseInfo, addResponse in + print("\(addResponse)") + return responseInfo + } } public static func reactionDelete( @@ -745,7 +749,11 @@ public enum OpenGroupAPI { ), using: dependencies ) - .map { responseInfo, _ in responseInfo } + .decoded(as: ReactionRemoveResponse.self, on: OpenGroupAPI.workQueue, using: dependencies) + .map { responseInfo, removeResponse in + print("\(removeResponse)") + return responseInfo + } } public static func reactionDeleteAll( @@ -772,7 +780,11 @@ public enum OpenGroupAPI { ), using: dependencies ) - .map { responseInfo, _ in responseInfo } + .decoded(as: ReactionRemoveAllResponse.self, on: OpenGroupAPI.workQueue, using: dependencies) + .map { responseInfo, removeAllResponse in + print("\(removeAllResponse)") + return responseInfo + } } // MARK: - Pinning From 543f729247507f20e89d304235a26b7c7ebb160a Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Thu, 25 Aug 2022 17:24:43 +1000 Subject: [PATCH 4/7] feat: add local cache and deal with merging for reaction changes --- Session.xcodeproj/project.pbxproj | 4 ++ .../ConversationVC+Interaction.swift | 30 +++++++++ SessionMessagingKit/Messages/Message.swift | 38 +++++++++--- .../Open Groups/Models/PendingChange.swift | 41 +++++++++++++ .../Open Groups/OpenGroupAPI.swift | 18 +----- .../Open Groups/OpenGroupManager.swift | 61 ++++++++++++++++++- 6 files changed, 167 insertions(+), 25 deletions(-) create mode 100644 SessionMessagingKit/Open Groups/Models/PendingChange.swift diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index 15c1cea40..81e1ae0a9 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -139,6 +139,7 @@ 7B81682328A4C1210069F315 /* UpdateTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B81682228A4C1210069F315 /* UpdateTypes.swift */; }; 7B81682828B310D50069F315 /* _007_HomeQueryOptimisationIndexes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B81682728B310D50069F315 /* _007_HomeQueryOptimisationIndexes.swift */; }; 7B81682A28B6F1420069F315 /* ReactionResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B81682928B6F1420069F315 /* ReactionResponse.swift */; }; + 7B81682C28B72F480069F315 /* PendingChange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B81682B28B72F480069F315 /* PendingChange.swift */; }; 7B8D5FC428332600008324D9 /* VisibleMessage+Reaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B8D5FC328332600008324D9 /* VisibleMessage+Reaction.swift */; }; 7B93D06A27CF173D00811CB6 /* MessageRequestsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B93D06927CF173D00811CB6 /* MessageRequestsViewController.swift */; }; 7B93D07027CF194000811CB6 /* ConfigurationMessage+Convenience.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B93D06E27CF194000811CB6 /* ConfigurationMessage+Convenience.swift */; }; @@ -1180,6 +1181,7 @@ 7B81682228A4C1210069F315 /* UpdateTypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateTypes.swift; sourceTree = ""; }; 7B81682728B310D50069F315 /* _007_HomeQueryOptimisationIndexes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = _007_HomeQueryOptimisationIndexes.swift; sourceTree = ""; }; 7B81682928B6F1420069F315 /* ReactionResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionResponse.swift; sourceTree = ""; }; + 7B81682B28B72F480069F315 /* PendingChange.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PendingChange.swift; sourceTree = ""; }; 7B8D5FC328332600008324D9 /* VisibleMessage+Reaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VisibleMessage+Reaction.swift"; sourceTree = ""; }; 7B93D06927CF173D00811CB6 /* MessageRequestsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageRequestsViewController.swift; sourceTree = ""; }; 7B93D06E27CF194000811CB6 /* ConfigurationMessage+Convenience.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ConfigurationMessage+Convenience.swift"; sourceTree = ""; }; @@ -3856,6 +3858,7 @@ FDC438A527BB113A00C60D73 /* UserUnbanRequest.swift */, FDC438A927BB12BB00C60D73 /* UserModeratorRequest.swift */, 7B81682928B6F1420069F315 /* ReactionResponse.swift */, + 7B81682B28B72F480069F315 /* PendingChange.swift */, ); path = Models; sourceTree = ""; @@ -5193,6 +5196,7 @@ C3471ECB2555356A00297E91 /* MessageSender+Encryption.swift in Sources */, FDF40CDE2897A1BC006A0CC4 /* _004_RemoveLegacyYDB.swift in Sources */, FDF0B74928060D13004C14C5 /* QuotedReplyModel.swift in Sources */, + 7B81682C28B72F480069F315 /* PendingChange.swift in Sources */, FD77289A284AF1BD0018502F /* Sodium+Utilities.swift in Sources */, FD5C7309285007920029977D /* BlindedIdLookup.swift in Sources */, 7B4C75CB26B37E0F0000AC89 /* UnsendRequest.swift in Sources */, diff --git a/Session/Conversations/ConversationVC+Interaction.swift b/Session/Conversations/ConversationVC+Interaction.swift index ff2ecc991..394810b2b 100644 --- a/Session/Conversations/ConversationVC+Interaction.swift +++ b/Session/Conversations/ConversationVC+Interaction.swift @@ -1137,6 +1137,14 @@ extension ConversationVC: else { return } if remove { + let pendingChange = OpenGroupManager + .addPendingReaction( + emoji: emoji, + id: openGroupServerMessageId, + in: openGroup.roomToken, + on: openGroup.server, + type: .remove + ) OpenGroupAPI .reactionDelete( db, @@ -1145,8 +1153,23 @@ extension ConversationVC: in: openGroup.roomToken, on: openGroup.server ) + .map { _, response in + OpenGroupManager + .updatePendingChange( + pendingChange, + seqNo: response.seqNo + ) + } .retainUntilComplete() } else { + let pendingChange = OpenGroupManager + .addPendingReaction( + emoji: emoji, + id: openGroupServerMessageId, + in: openGroup.roomToken, + on: openGroup.server, + type: .react + ) OpenGroupAPI .reactionAdd( db, @@ -1155,6 +1178,13 @@ extension ConversationVC: in: openGroup.roomToken, on: openGroup.server ) + .map { _, response in + OpenGroupManager + .updatePendingChange( + pendingChange, + seqNo: response.seqNo + ) + } .retainUntilComplete() } diff --git a/SessionMessagingKit/Messages/Message.swift b/SessionMessagingKit/Messages/Message.swift index f37f93f10..b16291a26 100644 --- a/SessionMessagingKit/Messages/Message.swift +++ b/SessionMessagingKit/Messages/Message.swift @@ -353,6 +353,7 @@ public extension Message { _ db: Database, openGroupId: String, message: OpenGroupAPI.Message, + associatedPendingChanges: [OpenGroupAPI.PendingChange], dependencies: SMKDependencies = SMKDependencies() ) -> [Reaction] { var results: [Reaction] = [] @@ -364,14 +365,33 @@ public extension Message { threadVariant: .openGroup ) for (encodedEmoji, rawReaction) in reactions { - if let emoji = encodedEmoji.removingPercentEncoding, + if let decodedEmoji = encodedEmoji.removingPercentEncoding, rawReaction.count > 0, let reactors = rawReaction.reactors { + // Decide whether we need to add an extra reaction from current user + let pendingChanges = associatedPendingChanges + .filter { + if case .reaction(_, let emoji, _) = $0.metadata { + return emoji == decodedEmoji + } + return false + } + var shouldAddSelfReaction: Bool = rawReaction.you || reactors.contains(userPublicKey) + pendingChanges.forEach { + if case .reaction(_, _, let action) = $0.metadata { + switch action { + case .react: shouldAddSelfReaction = true + case .remove: shouldAddSelfReaction = false + } + } + } + + let count: Int64 = shouldAddSelfReaction ? rawReaction.count - 1 : rawReaction.count let timestampMs: Int64 = Int64(floor((Date().timeIntervalSince1970 * 1000))) - let maxLength: Int = !rawReaction.you || reactors.contains(userPublicKey) ? 5 : 4 + let maxLength: Int = shouldAddSelfReaction ? 4 : 5 let desiredReactorIds: [String] = reactors - .filter { $0 != blindedUserPublicKey } + .filter { $0 != blindedUserPublicKey && $0 != userPublicKey } // Remove current user for now, will add back if needed .prefix(maxLength) .map{ $0 } @@ -384,8 +404,8 @@ public extension Message { serverHash: nil, timestampMs: timestampMs, authorId: reactor, - emoji: emoji, - count: rawReaction.count, + emoji: decodedEmoji, + count: count, sortId: rawReaction.index ) } @@ -401,22 +421,22 @@ public extension Message { serverHash: nil, timestampMs: timestampMs, authorId: reactor, - emoji: emoji, + emoji: decodedEmoji, count: 0, // Only want this on the first reaction sortId: rawReaction.index ) } ) .appending( // Add the current user reaction (if applicable and not already included) - !rawReaction.you || reactors.contains(userPublicKey) ? + !shouldAddSelfReaction ? nil : Reaction( interactionId: message.id, serverHash: nil, timestampMs: timestampMs, authorId: userPublicKey, - emoji: emoji, - count: (desiredReactorIds.isEmpty ? rawReaction.count : 0), + emoji: decodedEmoji, + count: 1, sortId: rawReaction.index ) ) diff --git a/SessionMessagingKit/Open Groups/Models/PendingChange.swift b/SessionMessagingKit/Open Groups/Models/PendingChange.swift new file mode 100644 index 000000000..1c9c3e513 --- /dev/null +++ b/SessionMessagingKit/Open Groups/Models/PendingChange.swift @@ -0,0 +1,41 @@ +// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. + +import Foundation + +extension OpenGroupAPI { + public struct PendingChange: Equatable { + enum ChangeType { + case reaction + } + + enum Metadata { + case reaction(messageId: Int64, emoji: String, action: VisibleMessage.VMReaction.Kind) + } + + let server: String + let room: String + let changeType: ChangeType + var seqNo: Int64? + let metadata: Metadata + + public static func == (lhs: OpenGroupAPI.PendingChange, rhs: OpenGroupAPI.PendingChange) -> Bool { + guard lhs.server == rhs.server && + lhs.room == rhs.room && + lhs.changeType == rhs.changeType && + lhs.seqNo == rhs.seqNo + else { + return false + } + + switch lhs.changeType { + case .reaction: + if case .reaction(let lhsMessageId, let lhsEmoji, let lhsAction) = lhs.metadata, + case .reaction(let rhsMessageId, let rhsEmoji, let rhsAction) = rhs.metadata { + return lhsMessageId == rhsMessageId && lhsEmoji == rhsEmoji && lhsAction == rhsAction + } else { + return false + } + } + } + } +} diff --git a/SessionMessagingKit/Open Groups/OpenGroupAPI.swift b/SessionMessagingKit/Open Groups/OpenGroupAPI.swift index 01ceb20fc..04cf63b57 100644 --- a/SessionMessagingKit/Open Groups/OpenGroupAPI.swift +++ b/SessionMessagingKit/Open Groups/OpenGroupAPI.swift @@ -701,7 +701,7 @@ public enum OpenGroupAPI { in roomToken: String, on server: String, using dependencies: SMKDependencies = SMKDependencies() - ) -> Promise { + ) -> Promise<(OnionRequestResponseInfoType, ReactionAddResponse)> { /// URL(String:) won't convert raw emojis, so need to do a little encoding here. /// The raw emoji will come back when calling url.path guard let encodedEmoji: String = emoji.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) else { @@ -719,10 +719,6 @@ public enum OpenGroupAPI { using: dependencies ) .decoded(as: ReactionAddResponse.self, on: OpenGroupAPI.workQueue, using: dependencies) - .map { responseInfo, addResponse in - print("\(addResponse)") - return responseInfo - } } public static func reactionDelete( @@ -732,7 +728,7 @@ public enum OpenGroupAPI { in roomToken: String, on server: String, using dependencies: SMKDependencies = SMKDependencies() - ) -> Promise { + ) -> Promise<(OnionRequestResponseInfoType, ReactionRemoveResponse)> { /// URL(String:) won't convert raw emojis, so need to do a little encoding here. /// The raw emoji will come back when calling url.path guard let encodedEmoji: String = emoji.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) else { @@ -750,10 +746,6 @@ public enum OpenGroupAPI { using: dependencies ) .decoded(as: ReactionRemoveResponse.self, on: OpenGroupAPI.workQueue, using: dependencies) - .map { responseInfo, removeResponse in - print("\(removeResponse)") - return responseInfo - } } public static func reactionDeleteAll( @@ -763,7 +755,7 @@ public enum OpenGroupAPI { in roomToken: String, on server: String, using dependencies: SMKDependencies = SMKDependencies() - ) -> Promise { + ) -> Promise<(OnionRequestResponseInfoType, ReactionRemoveAllResponse)> { /// URL(String:) won't convert raw emojis, so need to do a little encoding here. /// The raw emoji will come back when calling url.path guard let encodedEmoji: String = emoji.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) else { @@ -781,10 +773,6 @@ public enum OpenGroupAPI { using: dependencies ) .decoded(as: ReactionRemoveAllResponse.self, on: OpenGroupAPI.workQueue, using: dependencies) - .map { responseInfo, removeAllResponse in - print("\(removeAllResponse)") - return responseInfo - } } // MARK: - Pinning diff --git a/SessionMessagingKit/Open Groups/OpenGroupManager.swift b/SessionMessagingKit/Open Groups/OpenGroupManager.swift index 33fee96cc..4364a4dff 100644 --- a/SessionMessagingKit/Open Groups/OpenGroupManager.swift +++ b/SessionMessagingKit/Open Groups/OpenGroupManager.swift @@ -20,6 +20,8 @@ public protocol OGMCacheType { var timeSinceLastPoll: [String: TimeInterval] { get set } func getTimeSinceLastOpen(using dependencies: Dependencies) -> TimeInterval + + var pendingChanges: [OpenGroupAPI.PendingChange] { get set } } // MARK: - OpenGroupManager @@ -53,6 +55,8 @@ public final class OpenGroupManager: NSObject { _timeSinceLastOpen = dependencies.date.timeIntervalSince(lastOpen) return dependencies.date.timeIntervalSince(lastOpen) } + + public var pendingChanges: [OpenGroupAPI.PendingChange] = [] } // MARK: - Variables @@ -529,11 +533,17 @@ public final class OpenGroupManager: NSObject { .filter { $0.deleted == true } .map { $0.id } - // Update the 'openGroupSequenceNumber' value (Note: SOGS V4 uses the 'seqNo' instead of the 'serverId') if let seqNo: Int64 = seqNo { + // Update the 'openGroupSequenceNumber' value (Note: SOGS V4 uses the 'seqNo' instead of the 'serverId') _ = try? OpenGroup .filter(id: openGroup.id) .updateAll(db, OpenGroup.Columns.sequenceNumber.set(to: seqNo)) + + // Update pendingChange cache + dependencies.mutableCache.mutate { + $0.pendingChanges = $0.pendingChanges + .filter { $0.seqNo == nil || $0.seqNo! > seqNo } + } } // Process the messages @@ -589,6 +599,17 @@ public final class OpenGroupManager: NSObject { db, openGroupId: openGroup.id, message: message, + associatedPendingChanges: dependencies.cache.pendingChanges + .filter { + guard $0.server == server && $0.room == roomToken && $0.changeType == .reaction else { + return false + } + + if case .reaction(let messageId, _, _) = $0.metadata { + return messageId == message.id + } + return false + }, dependencies: dependencies ) @@ -738,6 +759,44 @@ public final class OpenGroupManager: NSObject { // MARK: - Convenience + public static func addPendingReaction( + emoji: String, + id: Int64, + in roomToken: String, + on server: String, + type: VisibleMessage.VMReaction.Kind, + using dependencies: OGMDependencies = OGMDependencies() + ) -> OpenGroupAPI.PendingChange { + let pendingChange = OpenGroupAPI.PendingChange( + server: server, + room: roomToken, + changeType: .reaction, + metadata: .reaction( + messageId: id, + emoji: emoji, + action: type + ) + ) + + dependencies.mutableCache.mutate { + $0.pendingChanges.append(pendingChange) + } + + return pendingChange + } + + public static func updatePendingChange( + _ pendingChange: OpenGroupAPI.PendingChange, + seqNo: Int64, + using dependencies: OGMDependencies = OGMDependencies() + ) { + dependencies.mutableCache.mutate { + if let index = $0.pendingChanges.firstIndex(of: pendingChange) { + $0.pendingChanges[index].seqNo = seqNo + } + } + } + /// This method specifies if the given capability is supported on a specified Open Group public static func isOpenGroupSupport( _ capability: Capability.Variant, From 81ef5a744a7cd44bc017aa5e4a3cfc0e69a25aae Mon Sep 17 00:00:00 2001 From: Ryan Zhao Date: Thu, 25 Aug 2022 17:28:48 +1000 Subject: [PATCH 5/7] fix count logic --- SessionMessagingKit/Messages/Message.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/SessionMessagingKit/Messages/Message.swift b/SessionMessagingKit/Messages/Message.swift index b16291a26..7b0765885 100644 --- a/SessionMessagingKit/Messages/Message.swift +++ b/SessionMessagingKit/Messages/Message.swift @@ -387,7 +387,8 @@ public extension Message { } } - let count: Int64 = shouldAddSelfReaction ? rawReaction.count - 1 : rawReaction.count + let count: Int64 = rawReaction.you ? rawReaction.count - 1 : rawReaction.count + let timestampMs: Int64 = Int64(floor((Date().timeIntervalSince1970 * 1000))) let maxLength: Int = shouldAddSelfReaction ? 4 : 5 let desiredReactorIds: [String] = reactors From ae639b2474fcda6378ed41e00df2b95b5f079e15 Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Fri, 26 Aug 2022 10:53:48 +1000 Subject: [PATCH 6/7] minor fix --- Session/Notifications/AppNotifications.swift | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Session/Notifications/AppNotifications.swift b/Session/Notifications/AppNotifications.swift index 96c6bea16..357b39c4a 100644 --- a/Session/Notifications/AppNotifications.swift +++ b/Session/Notifications/AppNotifications.swift @@ -384,9 +384,12 @@ public class NotificationPresenter: NSObject, NotificationsProtocol { closedGroupName: nil, // Not supported openGroupName: nil // Not supported ) + + let fallbackSound: Preferences.Sound = db[.defaultNotificationSound] + .defaulting(to: Preferences.Sound.defaultNotificationSound) DispatchQueue.main.async { - let sound = self.requestSound(thread: thread) + let sound = self.requestSound(thread: thread, fallbackSound: fallbackSound) self.adaptee.notify( category: category, From 29dd85ebe7450a607fba9bf89c9449b24e55854d Mon Sep 17 00:00:00 2001 From: ryanzhao Date: Fri, 26 Aug 2022 14:22:31 +1000 Subject: [PATCH 7/7] minor refactor --- SessionMessagingKit/Messages/Message.swift | 40 ++++++++++++++-------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/SessionMessagingKit/Messages/Message.swift b/SessionMessagingKit/Messages/Message.swift index 7b0765885..28c2b3f28 100644 --- a/SessionMessagingKit/Messages/Message.swift +++ b/SessionMessagingKit/Messages/Message.swift @@ -370,22 +370,32 @@ public extension Message { let reactors = rawReaction.reactors { // Decide whether we need to add an extra reaction from current user - let pendingChanges = associatedPendingChanges - .filter { - if case .reaction(_, let emoji, _) = $0.metadata { - return emoji == decodedEmoji - } - return false - } - var shouldAddSelfReaction: Bool = rawReaction.you || reactors.contains(userPublicKey) - pendingChanges.forEach { - if case .reaction(_, _, let action) = $0.metadata { - switch action { - case .react: shouldAddSelfReaction = true - case .remove: shouldAddSelfReaction = false + let pendingChangeSelfReaction: Bool? = { + // Find the newest 'PendingChange' entry with a matching emoji, if one exists, and + // set the "self reaction" value based on it's action + let maybePendingChange: OpenGroupAPI.PendingChange? = associatedPendingChanges + .sorted(by: { lhs, rhs -> Bool in (lhs.seqNo ?? Int64.max) > (rhs.seqNo ?? Int64.max) }) + .first { pendingChange in + if case .reaction(_, let emoji, _) = pendingChange.metadata { + return emoji == decodedEmoji + } + + return false } - } - } + + // If there is no pending change for this reaction then return nil + guard + let pendingChange: OpenGroupAPI.PendingChange = maybePendingChange, + case .reaction(_, _, let action) = pendingChange.metadata + else { return nil } + + // Otherwise add/remove accordingly + return (action == .react) + }() + let shouldAddSelfReaction: Bool = ( + pendingChangeSelfReaction ?? + (rawReaction.you || reactors.contains(userPublicKey)) + ) let count: Int64 = rawReaction.you ? rawReaction.count - 1 : rawReaction.count