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

138 lines
5.3 KiB
Swift

//
// Copyright 2024 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
/// Handles incoming `CallLogEvent` sync messages.
///
/// - SeeAlso ``IncomingCallLogEventSyncMessageParams``
protocol IncomingCallLogEventSyncMessageManager {
func handleIncomingSyncMessage(
incomingSyncMessage: IncomingCallLogEventSyncMessageParams,
tx: DBWriteTransaction
)
}
class IncomingCallLogEventSyncMessageManagerImpl: IncomingCallLogEventSyncMessageManager {
private let callRecordConversationIdAdapter: CallRecordSyncMessageConversationIdAdapter
private let deleteAllCallsJobQueue: Shims.DeleteAllCallsJobQueue
private let missedCallManager: CallRecordMissedCallManager
private var logger: CallRecordLogger { .shared }
init(
callRecordConversationIdAdapter: CallRecordSyncMessageConversationIdAdapter,
deleteAllCallsJobQueue: Shims.DeleteAllCallsJobQueue,
missedCallManager: CallRecordMissedCallManager
) {
self.callRecordConversationIdAdapter = callRecordConversationIdAdapter
self.deleteAllCallsJobQueue = deleteAllCallsJobQueue
self.missedCallManager = missedCallManager
}
func handleIncomingSyncMessage(
incomingSyncMessage: IncomingCallLogEventSyncMessageParams,
tx: DBWriteTransaction
) {
/// A `CallLogEvent` sync message contains information identifying a
/// call whose `callBeganTimestamp` serves as a "reference point" for
/// the bulk action the sync message describes. If for whatever reason
/// that call isn't available on this device, we'll fall back to the
/// timestamp embedded in the sync message.
let referencedCallRecord: CallRecord? = {
if let callIdentifiers = incomingSyncMessage.anchorCallIdentifiers {
do {
return try callRecordConversationIdAdapter.hydrate(
conversationId: callIdentifiers.conversationId,
callId: callIdentifiers.callId,
tx: tx
)
} catch {
owsFailDebug("\(error)")
}
}
return nil
}()
if let referencedCallRecord {
switch incomingSyncMessage.eventType {
case .cleared:
deleteAllCallsJobQueue.deleteAllCalls(
before: .callRecord(referencedCallRecord),
tx: tx
)
case .markedAsRead:
missedCallManager.markUnreadCallsAsRead(
beforeTimestamp: referencedCallRecord.callBeganTimestamp,
sendSyncMessage: false,
tx: tx
)
case .markedAsReadInConversation:
missedCallManager.markUnreadCallsInConversationAsRead(
beforeCallRecord: referencedCallRecord,
sendSyncMessage: false,
tx: tx
)
}
} else {
switch incomingSyncMessage.eventType {
case .cleared:
deleteAllCallsJobQueue.deleteAllCalls(
before: .timestamp(incomingSyncMessage.anchorTimestamp),
tx: tx
)
case .markedAsRead:
missedCallManager.markUnreadCallsAsRead(
beforeTimestamp: incomingSyncMessage.anchorTimestamp,
sendSyncMessage: false,
tx: tx
)
case .markedAsReadInConversation:
/// This case was added concurrently with the introduction of
/// call identifiers to the `CallLogEvent` sync message, and so
/// it's unexpected that we're missing the referenced call
/// record. We'd only expect this if the call record was deleted
/// on this device, so if we end up here: do nothing.
logger.warn("Received markedAsReadInConversation CallLogEvent sync message, but missing referenced call record!")
}
}
}
}
// MARK: - Mocks
extension IncomingCallLogEventSyncMessageManagerImpl {
enum Shims {
typealias DeleteAllCallsJobQueue = _IncomingCallLogEventSyncMessageManagerImpl_DeleteAllCallsJobQueue_Shim
}
enum Wrappers {
typealias DeleteAllCallsJobQueue = _IncomingCallLogEventSyncMessageManagerImpl_DeleteAllCallsJobQueue_Wrapper
}
}
protocol _IncomingCallLogEventSyncMessageManagerImpl_DeleteAllCallsJobQueue_Shim {
func deleteAllCalls(
before: CallRecordDeleteAllJobQueue.DeleteAllBeforeOptions,
tx: DBWriteTransaction
)
}
class _IncomingCallLogEventSyncMessageManagerImpl_DeleteAllCallsJobQueue_Wrapper: _IncomingCallLogEventSyncMessageManagerImpl_DeleteAllCallsJobQueue_Shim {
private let deleteAllCallsJobQueue: CallRecordDeleteAllJobQueue
init(_ deleteAllCallsJobQueue: CallRecordDeleteAllJobQueue) {
self.deleteAllCallsJobQueue = deleteAllCallsJobQueue
}
func deleteAllCalls(
before deleteAllBefore: CallRecordDeleteAllJobQueue.DeleteAllBeforeOptions,
tx: DBWriteTransaction
) {
deleteAllCallsJobQueue.addJob(
sendDeleteAllSyncMessage: false,
deleteAllBefore: deleteAllBefore,
tx: SDSDB.shimOnlyBridge(tx)
)
}
}