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

122 lines
4 KiB
Swift

//
// Copyright 2023 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import Foundation
public protocol SignalRecipientManager {
func fetchRecipientIfPhoneNumberVisible(
_ phoneNumber: String,
tx: DBReadTransaction
) -> SignalRecipient?
func modifyAndSave(
_ recipient: SignalRecipient,
deviceIdsToAdd: [UInt32],
deviceIdsToRemove: [UInt32],
shouldUpdateStorageService: Bool,
tx: DBWriteTransaction
)
func markAsUnregisteredAndSave(
_ recipient: SignalRecipient,
unregisteredAt: UnregisteredAt,
shouldUpdateStorageService: Bool,
tx: DBWriteTransaction
)
}
public enum UnregisteredAt {
case now
case specificTimeFromOtherDevice(UInt64)
}
extension SignalRecipientManager {
public func markAsRegisteredAndSave(
_ recipient: SignalRecipient,
deviceId: UInt32 = OWSDevice.primaryDeviceId,
shouldUpdateStorageService: Bool,
tx: DBWriteTransaction
) {
modifyAndSave(
recipient,
deviceIdsToAdd: [deviceId],
deviceIdsToRemove: [],
shouldUpdateStorageService: shouldUpdateStorageService,
tx: tx
)
}
}
public class SignalRecipientManagerImpl: SignalRecipientManager {
private let phoneNumberVisibilityFetcher: any PhoneNumberVisibilityFetcher
private let recipientDatabaseTable: any RecipientDatabaseTable
let storageServiceManager: any StorageServiceManager
public init(
phoneNumberVisibilityFetcher: any PhoneNumberVisibilityFetcher,
recipientDatabaseTable: any RecipientDatabaseTable,
storageServiceManager: any StorageServiceManager
) {
self.phoneNumberVisibilityFetcher = phoneNumberVisibilityFetcher
self.recipientDatabaseTable = recipientDatabaseTable
self.storageServiceManager = storageServiceManager
}
public func fetchRecipientIfPhoneNumberVisible(_ phoneNumber: String, tx: DBReadTransaction) -> SignalRecipient? {
let recipient = recipientDatabaseTable.fetchRecipient(phoneNumber: phoneNumber, transaction: tx)
guard let recipient else {
return nil
}
guard phoneNumberVisibilityFetcher.isPhoneNumberVisible(for: recipient, tx: tx) else {
return nil
}
return recipient
}
public func markAsUnregisteredAndSave(
_ recipient: SignalRecipient,
unregisteredAt: UnregisteredAt,
shouldUpdateStorageService: Bool,
tx: DBWriteTransaction
) {
if case .specificTimeFromOtherDevice(let timestamp) = unregisteredAt {
setUnregisteredAtTimestamp(timestamp, for: recipient, shouldUpdateStorageService: shouldUpdateStorageService)
}
modifyAndSave(
recipient,
deviceIdsToAdd: [],
deviceIdsToRemove: recipient.deviceIds,
shouldUpdateStorageService: shouldUpdateStorageService,
tx: tx
)
}
public func modifyAndSave(
_ recipient: SignalRecipient,
deviceIdsToAdd: [UInt32],
deviceIdsToRemove: [UInt32],
shouldUpdateStorageService: Bool,
tx: DBWriteTransaction
) {
var deviceIdsToAdd = deviceIdsToAdd
// Always add the primary if any other device is registered.
if !deviceIdsToAdd.isEmpty {
deviceIdsToAdd.append(OWSDevice.primaryDeviceId)
}
let oldDeviceIds = Set(recipient.deviceIds)
let newDeviceIds = oldDeviceIds.union(deviceIdsToAdd).subtracting(deviceIdsToRemove)
if oldDeviceIds == newDeviceIds {
return
}
Logger.info("Updating \(recipient.aci?.logString ?? recipient.pni?.logString ?? "<>")'s devices. Added \(newDeviceIds.subtracting(oldDeviceIds).sorted()). Removed \(oldDeviceIds.subtracting(newDeviceIds).sorted()).")
setDeviceIds(newDeviceIds, for: recipient, shouldUpdateStorageService: shouldUpdateStorageService)
recipientDatabaseTable.updateRecipient(recipient, transaction: tx)
}
}