Signal-iOS/SignalServiceKit/Contacts/Threads/TSPrivateStoryThread.swift
2024-03-27 12:22:52 -05:00

91 lines
4.1 KiB
Swift

//
// Copyright 2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import Foundation
public extension TSPrivateStoryThread {
@objc
var distributionListIdentifier: Data? { UUID(uuidString: uniqueId)?.data }
@objc
class var myStoryUniqueId: String {
// My Story always uses a UUID of all 0s
"00000000-0000-0000-0000-000000000000"
}
class func getMyStory(transaction: SDSAnyReadTransaction) -> TSPrivateStoryThread! {
anyFetchPrivateStoryThread(uniqueId: myStoryUniqueId, transaction: transaction)
}
@discardableResult
class func getOrCreateMyStory(transaction: SDSAnyWriteTransaction) -> TSPrivateStoryThread! {
if let myStory = getMyStory(transaction: transaction) { return myStory }
let myStory = TSPrivateStoryThread(uniqueId: myStoryUniqueId, name: "", allowsReplies: true, addresses: [], viewMode: .blockList)
myStory.anyInsert(transaction: transaction)
return myStory
}
override func recipientAddresses(with transaction: SDSAnyReadTransaction) -> [SignalServiceAddress] {
switch storyViewMode {
case .default:
owsFailDebug("Unexpectedly have private story with no view mode")
return []
case .explicit, .disabled:
return addresses
case .blockList:
return profileManager.allWhitelistedRegisteredAddresses(tx: transaction).filter { !addresses.contains($0) && !$0.isLocalAddress }
}
}
private static let deletedAtTimestampKVS = SDSKeyValueStore(collection: "TSPrivateStoryThread+DeletedAtTimestamp")
private static let deletedAtTimestampThreshold = kMonthInterval
static func deletedAtTimestamp(forDistributionListIdentifier identifier: Data, transaction: SDSAnyReadTransaction) -> UInt64? {
guard let uniqueId = UUID(data: identifier)?.uuidString else { return nil }
return deletedAtTimestampKVS.getUInt64(uniqueId, transaction: transaction)
}
static func recordDeletedAtTimestamp(_ timestamp: UInt64, forDistributionListIdentifier identifier: Data, transaction: SDSAnyWriteTransaction) {
guard Date().timeIntervalSince(Date(millisecondsSince1970: timestamp)) < deletedAtTimestampThreshold else {
Logger.warn("Ignorning stale deleted at timestamp")
return
}
guard let uniqueId = UUID(data: identifier)?.uuidString else { return }
deletedAtTimestampKVS.setUInt64(timestamp, key: uniqueId, transaction: transaction)
}
static func allDeletedIdentifiers(transaction: SDSAnyReadTransaction) -> [Data] {
deletedAtTimestampKVS.allKeys(transaction: transaction).compactMap { UUID(uuidString: $0)?.data }
}
static func cleanupDeletedTimestamps(transaction tx: SDSAnyWriteTransaction) {
var deletedIdentifiers = [Data]()
for identifier in deletedAtTimestampKVS.allKeys(transaction: tx) {
guard let timestamp = deletedAtTimestampKVS.getUInt64(
identifier,
transaction: tx
) else { continue }
guard Date().timeIntervalSince(Date(millisecondsSince1970: timestamp)) > deletedAtTimestampThreshold else { continue }
deletedAtTimestampKVS.removeValue(forKey: identifier, transaction: tx)
// If we still have a private story thread for this deleted timestamp, it's
// now safe to purge it from the database.
if let thread = TSPrivateStoryThread.anyFetchPrivateStoryThread(uniqueId: identifier, transaction: tx) {
DependenciesBridge.shared.threadRemover.remove(thread, tx: tx.asV2Write)
}
UUID(uuidString: identifier).map { deletedIdentifiers.append($0.data) }
}
Self.storageServiceManager.recordPendingUpdates(updatedStoryDistributionListIds: deletedIdentifiers)
}
override func updateWithShouldThreadBeVisible(_ shouldThreadBeVisible: Bool, transaction: SDSAnyWriteTransaction) {
super.updateWithShouldThreadBeVisible(shouldThreadBeVisible, transaction: transaction)
updateWithStoryViewMode(.disabled, transaction: transaction)
}
}