Signal-iOS/SignalServiceKit/Devices/OWSDeviceManager.swift

124 lines
3.5 KiB
Swift

//
// Copyright 2023 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import Foundation
public protocol OWSDeviceManager {
func warmCaches()
// MARK: Has received sync message
func setHasReceivedSyncMessage(
lastReceivedAt: Date,
transaction: DBWriteTransaction
)
func hasReceivedSyncMessage(inLastSeconds seconds: UInt) -> Bool
// MARK: May have linked devices
func setMayHaveLinkedDevices(
_ mayHaveLinkedDevices: Bool,
transaction: DBWriteTransaction
)
func mayHaveLinkedDevices(transaction: DBReadTransaction) -> Bool
}
extension OWSDeviceManager {
func setHasReceivedSyncMessage(transaction: DBWriteTransaction) {
setHasReceivedSyncMessage(lastReceivedAt: Date(), transaction: transaction)
}
}
class OWSDeviceManagerImpl: OWSDeviceManager {
private enum Constants {
static let keyValueStoreCollectionName = "kTSStorageManager_OWSDeviceCollection"
static let mayHaveLinkedDevicesKey = "kTSStorageManager_MayHaveLinkedDevices"
static let lastReceivedSyncMessageKey = "kLastReceivedSyncMessage"
}
private let databaseStorage: DB
private let keyValueStore: KeyValueStore
private var lastReceivedSyncMessageAt: AtomicOptional<Date> = .init(nil, lock: .init())
init(
databaseStorage: DB,
keyValueStoreFactory: KeyValueStoreFactory
) {
self.databaseStorage = databaseStorage
keyValueStore = keyValueStoreFactory.keyValueStore(
collection: Constants.keyValueStoreCollectionName
)
}
func warmCaches() {
databaseStorage.read { transaction in
if let lastReceived = keyValueStore.getDate(
Constants.lastReceivedSyncMessageKey,
transaction: transaction
) {
_ = lastReceivedSyncMessageAt.tryToSetIfNil(lastReceived)
}
}
}
// MARK: Has received sync message
func hasReceivedSyncMessage(inLastSeconds lastSeconds: UInt) -> Bool {
guard let lastReceivedSyncMessageAt = lastReceivedSyncMessageAt.get() else {
return false
}
let timeIntervalSinceLastReceived = fabs(lastReceivedSyncMessageAt.timeIntervalSinceNow)
return timeIntervalSinceLastReceived < Double(lastSeconds)
}
func setHasReceivedSyncMessage(
lastReceivedAt: Date,
transaction: DBWriteTransaction
) {
self.lastReceivedSyncMessageAt.set(lastReceivedAt)
keyValueStore.setDate(
lastReceivedAt,
key: Constants.lastReceivedSyncMessageKey,
transaction: transaction
)
setMayHaveLinkedDevices(true, transaction: transaction)
}
// MARK: May have linked devices
/// Returns whether or not we may have linked devices.
///
/// By default, returns `true`. If we confirm we have no linked devices,
/// we should set this flag to `false` via ``setMayHaveLinkedDevices`` so
/// as to avoid unnecessary sync message sending.
func mayHaveLinkedDevices(transaction: DBReadTransaction) -> Bool {
return keyValueStore.getBool(
Constants.mayHaveLinkedDevicesKey,
defaultValue: true,
transaction: transaction
)
}
func setMayHaveLinkedDevices(
_ mayHaveLinkedDevices: Bool,
transaction: DBWriteTransaction
) {
keyValueStore.setBool(
mayHaveLinkedDevices,
key: Constants.mayHaveLinkedDevicesKey,
transaction: transaction
)
}
}