TM-SGNL-iOS/SignalServiceKit/GroupMembers/GroupMemberMergeObserver.swift
TeleMessage developers dde0620daf initial commit
2025-05-03 12:28:28 -07:00

73 lines
2.9 KiB
Swift

//
// Copyright 2023 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import Foundation
import LibSignalClient
class GroupMemberMergeObserverImpl: RecipientMergeObserver {
private let threadStore: ThreadStore
private let groupMemberUpdater: GroupMemberUpdater
private let groupMemberStore: GroupMemberStore
init(
threadStore: ThreadStore,
groupMemberUpdater: GroupMemberUpdater,
groupMemberStore: GroupMemberStore
) {
self.threadStore = threadStore
self.groupMemberUpdater = groupMemberUpdater
self.groupMemberStore = groupMemberStore
}
func willBreakAssociation(for recipient: SignalRecipient, mightReplaceNonnilPhoneNumber: Bool, tx: DBWriteTransaction) {}
func didLearnAssociation(mergedRecipient: MergedRecipient, tx: DBWriteTransaction) {
var groupThreadIds = [String]()
if let aci = mergedRecipient.newRecipient.aci {
groupThreadIds.append(contentsOf: groupMemberStore.groupThreadIds(withFullMember: aci, tx: tx))
}
if let phoneNumber = E164(mergedRecipient.newRecipient.phoneNumber?.stringValue) {
groupThreadIds.append(contentsOf: groupMemberStore.groupThreadIds(withFullMember: phoneNumber, tx: tx))
}
if let pni = mergedRecipient.newRecipient.pni {
groupThreadIds.append(contentsOf: groupMemberStore.groupThreadIds(withFullMember: pni, tx: tx))
}
resolveGroupMembers(in: groupThreadIds, tx: tx)
}
private func resolveGroupMembers(in groupThreadIds: [String], tx: DBWriteTransaction) {
for threadId in Set(groupThreadIds) {
guard let thread = threadStore.fetchGroupThread(uniqueId: threadId, tx: tx) else {
continue
}
mergeV1GroupMembersIfNeeded(in: thread, tx: tx)
groupMemberUpdater.updateRecords(groupThread: thread, transaction: tx)
}
}
private func mergeV1GroupMembersIfNeeded(in groupThread: TSGroupThread, tx: DBWriteTransaction) {
let oldGroupModel = groupThread.groupModel
// In V2 groups, we always have ACIs for full members, so we never need to
// merge them. For invited group members, we may have PNIs, but we leave
// the PNI in the list of invitations until it's accepted.
guard oldGroupModel.groupsVersion == .V1 else {
return
}
let newGroupModel: TSGroupModel
do {
// Creating a builder & building it will prune any duplicate addresses.
newGroupModel = try oldGroupModel.asBuilder.build()
} catch {
Logger.warn("Couldn't merge V1 group members.")
return
}
if oldGroupModel.groupMembership == newGroupModel.groupMembership {
return
}
groupThread.update(with: newGroupModel, transaction: SDSDB.shimOnlyBridge(tx))
}
}