Modernize CallRecordStore, CallLinkRecordStore
This commit is contained in:
parent
a9e3580fb4
commit
a49428670a
@ -9,7 +9,7 @@ import SignalServiceKit
|
||||
|
||||
final class AdHocCallStateObserver {
|
||||
private let adHocCallRecordManager: any AdHocCallRecordManager
|
||||
private let callLinkStore: any CallLinkRecordStore
|
||||
private let callLinkStore: CallLinkRecordStore
|
||||
private let db: any DB
|
||||
private let messageSenderJobQueue: MessageSenderJobQueue
|
||||
|
||||
@ -32,7 +32,7 @@ final class AdHocCallStateObserver {
|
||||
init(
|
||||
callLinkCall: CallLinkCall,
|
||||
adHocCallRecordManager: any AdHocCallRecordManager,
|
||||
callLinkStore: any CallLinkRecordStore,
|
||||
callLinkStore: CallLinkRecordStore,
|
||||
messageSenderJobQueue: MessageSenderJobQueue,
|
||||
db: any DB,
|
||||
) {
|
||||
@ -62,33 +62,29 @@ final class AdHocCallStateObserver {
|
||||
}
|
||||
self.furthestJoinLevel = joinLevel
|
||||
db.write { tx in
|
||||
do {
|
||||
let rootKey = callLinkCall.callLink.rootKey
|
||||
var (callLink, inserted) = try callLinkStore.fetchOrInsert(rootKey: rootKey, tx: tx)
|
||||
if inserted {
|
||||
callLink.updateState(callLinkCall.callLinkState)
|
||||
try callLinkStore.update(callLink, tx: tx)
|
||||
}
|
||||
if callLink.adminPasskey == nil, !callLink.isDeleted {
|
||||
let updateSender = CallLinkUpdateMessageSender(messageSenderJobQueue: messageSenderJobQueue)
|
||||
updateSender.sendCallLinkUpdateMessage(rootKey: rootKey, adminPasskey: nil, tx: tx)
|
||||
}
|
||||
try adHocCallRecordManager.createOrUpdateRecord(
|
||||
callId: callIdFromEra(eraId),
|
||||
callLink: callLink,
|
||||
status: { () -> CallRecord.CallStatus.CallLinkCallStatus in
|
||||
switch joinLevel {
|
||||
case .attempted: return .generic
|
||||
case .joined: return .joined
|
||||
}
|
||||
}(),
|
||||
timestamp: Date.ows_millisecondTimestamp(),
|
||||
shouldSendSyncMessge: true,
|
||||
tx: tx,
|
||||
)
|
||||
} catch {
|
||||
owsFailDebug("Couldn't update CallRecord: \(error)")
|
||||
let rootKey = callLinkCall.callLink.rootKey
|
||||
var (callLink, inserted) = callLinkStore.fetchOrInsert(rootKey: rootKey, tx: tx)
|
||||
if inserted {
|
||||
callLink.updateState(callLinkCall.callLinkState)
|
||||
callLinkStore.update(callLink, tx: tx)
|
||||
}
|
||||
if callLink.adminPasskey == nil, !callLink.isDeleted {
|
||||
let updateSender = CallLinkUpdateMessageSender(messageSenderJobQueue: messageSenderJobQueue)
|
||||
updateSender.sendCallLinkUpdateMessage(rootKey: rootKey, adminPasskey: nil, tx: tx)
|
||||
}
|
||||
adHocCallRecordManager.createOrUpdateRecord(
|
||||
callId: callIdFromEra(eraId),
|
||||
callLink: callLink,
|
||||
status: { () -> CallRecord.CallStatus.CallLinkCallStatus in
|
||||
switch joinLevel {
|
||||
case .attempted: return .generic
|
||||
case .joined: return .joined
|
||||
}
|
||||
}(),
|
||||
timestamp: Date.ows_millisecondTimestamp(),
|
||||
shouldSendSyncMessge: true,
|
||||
tx: tx,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -105,15 +101,11 @@ final class AdHocCallStateObserver {
|
||||
}
|
||||
self.activeEraId = .some(peekInfo.eraId)
|
||||
db.write { tx in
|
||||
do {
|
||||
try adHocCallRecordManager.handlePeekResult(
|
||||
eraId: peekInfo.eraId,
|
||||
rootKey: self.callLinkCall.callLink.rootKey,
|
||||
tx: tx,
|
||||
)
|
||||
} catch {
|
||||
owsFailDebug("\(error)")
|
||||
}
|
||||
adHocCallRecordManager.handlePeekResult(
|
||||
eraId: peekInfo.eraId,
|
||||
rootKey: self.callLinkCall.callLink.rootKey,
|
||||
tx: tx,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,12 +8,12 @@ import SignalServiceKit
|
||||
|
||||
/// Refreshes call links that need to be updated.
|
||||
actor CallLinkFetchJobRunner: DatabaseChangeDelegate {
|
||||
private let callLinkStore: any CallLinkRecordStore
|
||||
private let callLinkStore: CallLinkRecordStore
|
||||
private let callLinkStateUpdater: CallLinkStateUpdater
|
||||
private let db: any DB
|
||||
|
||||
init(
|
||||
callLinkStore: any CallLinkRecordStore,
|
||||
callLinkStore: CallLinkRecordStore,
|
||||
callLinkStateUpdater: CallLinkStateUpdater,
|
||||
db: any DB,
|
||||
) {
|
||||
@ -52,13 +52,8 @@ actor CallLinkFetchJobRunner: DatabaseChangeDelegate {
|
||||
|
||||
var sequentialFailureCount = 0
|
||||
while true {
|
||||
let callLinkToFetch: CallLinkRecord?
|
||||
do {
|
||||
callLinkToFetch = try db.read(block: callLinkStore.fetchAnyPendingRecord(tx:))
|
||||
} catch {
|
||||
owsFailDebug("Can't fetch pending record: \(error)")
|
||||
mightHavePendingFetch = false
|
||||
return
|
||||
let callLinkToFetch = db.read { tx in
|
||||
callLinkStore.fetchAnyPendingRecord(tx: tx)
|
||||
}
|
||||
guard let callLinkToFetch else {
|
||||
// Nothing to fetch.
|
||||
|
||||
@ -18,7 +18,7 @@ actor CallLinkStateUpdater {
|
||||
private let authCredentialManager: any AuthCredentialManager
|
||||
private let callLinkFetcher: CallLinkFetcherImpl
|
||||
private let callLinkManager: any CallLinkManager
|
||||
private let callLinkStore: any CallLinkRecordStore
|
||||
private let callLinkStore: CallLinkRecordStore
|
||||
private let callRecordDeleteManager: any CallRecordDeleteManager
|
||||
private let callRecordStore: any CallRecordStore
|
||||
private let db: any DB
|
||||
@ -30,7 +30,7 @@ actor CallLinkStateUpdater {
|
||||
authCredentialManager: any AuthCredentialManager,
|
||||
callLinkFetcher: CallLinkFetcherImpl,
|
||||
callLinkManager: any CallLinkManager,
|
||||
callLinkStore: any CallLinkRecordStore,
|
||||
callLinkStore: CallLinkRecordStore,
|
||||
callRecordDeleteManager: any CallRecordDeleteManager,
|
||||
callRecordStore: any CallRecordStore,
|
||||
db: any DB,
|
||||
@ -90,8 +90,8 @@ actor CallLinkStateUpdater {
|
||||
}
|
||||
|
||||
let registeredState = try tsAccountManager.registeredStateWithMaybeSneakyTransaction()
|
||||
let oldRecord = try db.read { tx -> CallLinkRecord? in
|
||||
return try callLinkStore.fetch(roomId: roomId, tx: tx)
|
||||
let oldRecord = db.read { tx -> CallLinkRecord? in
|
||||
return callLinkStore.fetch(roomId: roomId, tx: tx)
|
||||
}
|
||||
let authCredential = try await authCredentialManager.fetchCallLinkAuthCredential(localIdentifiers: registeredState.localIdentifiers)
|
||||
let updateResult = await Result { try await updateAndFetch(authCredential) }
|
||||
@ -113,8 +113,8 @@ actor CallLinkStateUpdater {
|
||||
throw error
|
||||
}
|
||||
|
||||
try await db.awaitableWrite { tx in
|
||||
if var newRecord = try self.callLinkStore.fetch(roomId: roomId, tx: tx) {
|
||||
await db.awaitableWrite { tx in
|
||||
if var newRecord = self.callLinkStore.fetch(roomId: roomId, tx: tx) {
|
||||
if !newRecord.isDeleted {
|
||||
switch updateAction {
|
||||
case .update(let newState):
|
||||
@ -123,7 +123,7 @@ actor CallLinkStateUpdater {
|
||||
break
|
||||
case .delete:
|
||||
newRecord.markDeleted(atTimestampMs: Date.ows_millisecondTimestamp())
|
||||
try self.callRecordDeleteManager.deleteCallRecords(
|
||||
self.callRecordDeleteManager.deleteCallRecords(
|
||||
self.callRecordStore.fetchExisting(conversationId: .callLink(callLinkRowId: newRecord.id), limit: nil, tx: tx),
|
||||
sendSyncMessageOnDelete: true,
|
||||
tx: tx,
|
||||
@ -133,7 +133,7 @@ actor CallLinkStateUpdater {
|
||||
if newRecord.pendingFetchCounter == oldRecord?.pendingFetchCounter {
|
||||
newRecord.clearNeedsFetch()
|
||||
}
|
||||
try self.callLinkStore.update(newRecord, tx: tx)
|
||||
self.callLinkStore.update(newRecord, tx: tx)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -27,7 +27,7 @@ final class CallService: CallServiceStateObserver, CallServiceStateDelegate {
|
||||
private var adHocCallRecordManager: any AdHocCallRecordManager { DependenciesBridge.shared.adHocCallRecordManager }
|
||||
private let appReadiness: AppReadiness
|
||||
private var audioSession: AudioSession { SUIEnvironment.shared.audioSessionRef }
|
||||
private var callLinkStore: any CallLinkRecordStore { DependenciesBridge.shared.callLinkStore }
|
||||
private var callLinkStore: CallLinkRecordStore { DependenciesBridge.shared.callLinkStore }
|
||||
private var chatConnectionManager: any ChatConnectionManager { DependenciesBridge.shared.chatConnectionManager }
|
||||
let authCredentialManager: any AuthCredentialManager
|
||||
private var databaseStorage: SDSDatabaseStorage { SSKEnvironment.shared.databaseStorageRef }
|
||||
@ -91,7 +91,7 @@ final class CallService: CallServiceStateObserver, CallServiceStateDelegate {
|
||||
appReadiness: AppReadiness,
|
||||
authCredentialManager: any AuthCredentialManager,
|
||||
callLinkPublicParams: GenericServerPublicParams,
|
||||
callLinkStore: any CallLinkRecordStore,
|
||||
callLinkStore: CallLinkRecordStore,
|
||||
callRecordDeleteManager: any CallRecordDeleteManager,
|
||||
callRecordStore: any CallRecordStore,
|
||||
callServiceSettingsStore: CallServiceSettingsStore,
|
||||
@ -658,8 +658,8 @@ final class CallService: CallServiceStateObserver, CallServiceStateDelegate {
|
||||
}
|
||||
let localIdentifiers = DependenciesBridge.shared.tsAccountManager.localIdentifiersWithMaybeSneakyTransaction!
|
||||
let authCredential = try await authCredentialManager.fetchCallLinkAuthCredential(localIdentifiers: localIdentifiers)
|
||||
let (adminPasskey, isDeleted) = try databaseStorage.read { tx -> (Data?, Bool) in
|
||||
let callLinkRecord = try callLinkStore.fetch(roomId: callLink.rootKey.deriveRoomId(), tx: tx)
|
||||
let (adminPasskey, isDeleted) = databaseStorage.read { tx -> (Data?, Bool) in
|
||||
let callLinkRecord = callLinkStore.fetch(roomId: callLink.rootKey.deriveRoomId(), tx: tx)
|
||||
return (callLinkRecord?.adminPasskey, callLinkRecord?.isDeleted == true)
|
||||
}
|
||||
let serverPublicParams = CallService.serverPublicParams()
|
||||
|
||||
@ -282,20 +282,16 @@ private extension GroupCallRecordManager {
|
||||
}
|
||||
|
||||
logger.info("Creating or updating record for group call join.")
|
||||
do {
|
||||
try createOrUpdateCallRecord(
|
||||
callId: callId,
|
||||
groupThread: groupThread,
|
||||
groupThreadRowId: groupThreadRowId,
|
||||
callDirection: callDirection,
|
||||
groupCallStatus: groupCallStatus,
|
||||
callEventTimestamp: joinTimestamp,
|
||||
shouldSendSyncMessage: true,
|
||||
tx: tx,
|
||||
)
|
||||
} catch let error {
|
||||
owsFailBeta("Failed to insert call record: \(error)")
|
||||
}
|
||||
createOrUpdateCallRecord(
|
||||
callId: callId,
|
||||
groupThread: groupThread,
|
||||
groupThreadRowId: groupThreadRowId,
|
||||
callDirection: callDirection,
|
||||
groupCallStatus: groupCallStatus,
|
||||
callEventTimestamp: joinTimestamp,
|
||||
shouldSendSyncMessage: true,
|
||||
tx: tx,
|
||||
)
|
||||
}
|
||||
|
||||
/// Create or update a call record in response to the local declining a ring
|
||||
@ -314,19 +310,15 @@ private extension GroupCallRecordManager {
|
||||
}
|
||||
|
||||
logger.info("Creating or updating record for group ring decline.")
|
||||
do {
|
||||
try createOrUpdateCallRecord(
|
||||
callId: callIdFromRingId(ringId),
|
||||
groupThread: groupThread,
|
||||
groupThreadRowId: groupThreadRowId,
|
||||
callDirection: .incoming,
|
||||
groupCallStatus: .ringingDeclined,
|
||||
callEventTimestamp: Date().ows_millisecondsSince1970,
|
||||
shouldSendSyncMessage: true,
|
||||
tx: tx,
|
||||
)
|
||||
} catch let error {
|
||||
owsFailBeta("Failed to insert call record: \(error)")
|
||||
}
|
||||
createOrUpdateCallRecord(
|
||||
callId: callIdFromRingId(ringId),
|
||||
groupThread: groupThread,
|
||||
groupThreadRowId: groupThreadRowId,
|
||||
callDirection: .incoming,
|
||||
groupCallStatus: .ringingDeclined,
|
||||
callEventTimestamp: Date().ows_millisecondsSince1970,
|
||||
shouldSendSyncMessage: true,
|
||||
tx: tx,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,7 +14,7 @@ final class CallLinkViewController: OWSTableViewController2 {
|
||||
override var navbarBackgroundColorOverride: UIColor? { tableBackgroundColor }
|
||||
|
||||
private var db: any DB { DependenciesBridge.shared.db }
|
||||
private var callLinkStore: any CallLinkRecordStore { DependenciesBridge.shared.callLinkStore }
|
||||
private var callLinkStore: CallLinkRecordStore { DependenciesBridge.shared.callLinkStore }
|
||||
|
||||
private let callLink: CallLink
|
||||
|
||||
@ -259,14 +259,10 @@ final class CallLinkViewController: OWSTableViewController2 {
|
||||
private func createCallLinkRecord() -> Int64 {
|
||||
let rowId = SSKEnvironment.shared.databaseStorageRef.write { tx in
|
||||
var callLinkRecord: CallLinkRecord
|
||||
do {
|
||||
(callLinkRecord, _) = try callLinkStore.fetchOrInsert(rootKey: callLink.rootKey, tx: tx)
|
||||
callLinkRecord.adminPasskey = adminPasskey!
|
||||
callLinkRecord.updateState(callLinkState!)
|
||||
try callLinkStore.update(callLinkRecord, tx: tx)
|
||||
} catch {
|
||||
owsFail("Couldn't create CallLinkRecord: \(error)")
|
||||
}
|
||||
(callLinkRecord, _) = callLinkStore.fetchOrInsert(rootKey: callLink.rootKey, tx: tx)
|
||||
callLinkRecord.adminPasskey = adminPasskey!
|
||||
callLinkRecord.updateState(callLinkState!)
|
||||
callLinkStore.update(callLinkRecord, tx: tx)
|
||||
|
||||
CallLinkUpdateMessageSender(
|
||||
messageSenderJobQueue: SSKEnvironment.shared.messageSenderJobQueueRef,
|
||||
@ -333,19 +329,14 @@ final class CallLinkViewController: OWSTableViewController2 {
|
||||
extension CallLinkViewController: DatabaseChangeDelegate {
|
||||
private func loadStateAndReloadViewIfNeeded(callLinkRowId: Int64) {
|
||||
let didChangeVisibleProperty: Bool
|
||||
do {
|
||||
let oldState = self.callLinkState
|
||||
let newState = try self.db.read { tx in try callLinkStore.fetch(rowId: callLinkRowId, tx: tx)?.state }
|
||||
didChangeVisibleProperty = (
|
||||
(oldState == nil) != (newState == nil)
|
||||
|| (oldState?.name != newState?.name)
|
||||
|| (oldState?.requiresAdminApproval != newState?.requiresAdminApproval),
|
||||
)
|
||||
self.callLinkState = newState
|
||||
} catch {
|
||||
owsFailDebug("Couldn't fetch CallLink: \(error)")
|
||||
return
|
||||
}
|
||||
let oldState = self.callLinkState
|
||||
let newState = self.db.read { tx in callLinkStore.fetch(rowId: callLinkRowId, tx: tx)?.state }
|
||||
didChangeVisibleProperty = (
|
||||
(oldState == nil) != (newState == nil)
|
||||
|| (oldState?.name != newState?.name)
|
||||
|| (oldState?.requiresAdminApproval != newState?.requiresAdminApproval),
|
||||
)
|
||||
self.callLinkState = newState
|
||||
if didChangeVisibleProperty, self.isViewLoaded {
|
||||
updateContents(shouldReload: true)
|
||||
}
|
||||
|
||||
@ -49,7 +49,7 @@ extension CallsListViewController {
|
||||
case newer
|
||||
}
|
||||
|
||||
private let callLinkStore: any CallLinkRecordStore
|
||||
private let callLinkStore: CallLinkRecordStore
|
||||
private let callRecordLoader: CallRecordLoader
|
||||
private let callViewModelForCallRecords: CallViewModelForCallRecords
|
||||
private let callViewModelForUpcomingCallLink: CallViewModelForUpcomingCallLink
|
||||
@ -59,7 +59,7 @@ extension CallsListViewController {
|
||||
private let maxCoalescedCallsInOneViewModel: Int
|
||||
|
||||
init(
|
||||
callLinkStore: any CallLinkRecordStore,
|
||||
callLinkStore: CallLinkRecordStore,
|
||||
callRecordLoader: CallRecordLoader,
|
||||
callViewModelForCallRecords: @escaping CallViewModelForCallRecords,
|
||||
callViewModelForUpcomingCallLink: @escaping CallViewModelForUpcomingCallLink,
|
||||
@ -233,13 +233,7 @@ extension CallsListViewController {
|
||||
guard shouldFetchUpcomingCallLinks else {
|
||||
return
|
||||
}
|
||||
let upcomingCallLinks: [CallLinkRecord]
|
||||
do {
|
||||
upcomingCallLinks = try callLinkStore.fetchUpcoming(earlierThan: nil, limit: 2048, tx: tx)
|
||||
} catch {
|
||||
Logger.warn("Couldn't fetch call links to show on the calls tab: \(error)")
|
||||
return
|
||||
}
|
||||
let upcomingCallLinks = callLinkStore.fetchUpcoming(earlierThan: nil, limit: 2048, tx: tx)
|
||||
self.upcomingCallLinkReferences = upcomingCallLinks.map {
|
||||
return UpcomingCallLinkReference(callLinkRowId: $0.id)
|
||||
}
|
||||
|
||||
@ -36,7 +36,7 @@ class CallsListViewController: OWSViewController, HomeTabViewController, CallSer
|
||||
let adHocCallRecordManager: any AdHocCallRecordManager
|
||||
let badgeManager: BadgeManager
|
||||
let blockingManager: BlockingManager
|
||||
let callLinkStore: any CallLinkRecordStore
|
||||
let callLinkStore: CallLinkRecordStore
|
||||
let callRecordDeleteAllJobQueue: CallRecordDeleteAllJobQueue
|
||||
let callRecordDeleteManager: any CallRecordDeleteManager
|
||||
let callRecordMissedCallManager: CallRecordMissedCallManager
|
||||
@ -416,12 +416,12 @@ class CallsListViewController: OWSViewController, HomeTabViewController, CallSer
|
||||
// because they must first be deleted on the server. (We delete them
|
||||
// individually at the end of this method.)
|
||||
let callLinksToDelete: [(rootKey: CallLinkRootKey, adminPasskey: Data)]
|
||||
callLinksToDelete = (try? self.deps.callLinkStore.fetchAll(tx: tx).compactMap {
|
||||
callLinksToDelete = self.deps.callLinkStore.fetchAll(tx: tx).compactMap {
|
||||
guard let adminPasskey = $0.adminPasskey else {
|
||||
return nil
|
||||
}
|
||||
return ($0.rootKey, adminPasskey)
|
||||
}) ?? []
|
||||
}
|
||||
/// Delete-all should use the timestamp of the most-recent call, at
|
||||
/// the time the action was initiated, as the timestamp we delete
|
||||
/// before (and include in the outgoing sync message).
|
||||
@ -720,7 +720,7 @@ class CallsListViewController: OWSViewController, HomeTabViewController, CallSer
|
||||
// Query the database separately when starting & ending calls because the
|
||||
// row will usually be inserted during the call (ie `rowId` may be nil when
|
||||
// starting the call but nonnil when ending the very same call).
|
||||
let rowId = deps.db.read { tx in try? deps.callLinkStore.fetch(roomId: call.callLink.rootKey.deriveRoomId(), tx: tx)?.id }
|
||||
let rowId = deps.db.read { tx in deps.callLinkStore.fetch(roomId: call.callLink.rootKey.deriveRoomId(), tx: tx)?.id }
|
||||
guard let rowId else {
|
||||
// If you open the lobby for an ongoing call that you've never joined,
|
||||
// we'll call this method after the peek succeeds. However, you haven't
|
||||
@ -1015,13 +1015,8 @@ class CallsListViewController: OWSViewController, HomeTabViewController, CallSer
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
do {
|
||||
return try deps.callLinkStore.fetch(rowId: callLinkRowId, tx: tx) ?? {
|
||||
owsFail("Couldn't load CallLinkRecord that must exist!")
|
||||
}()
|
||||
} catch {
|
||||
owsFail("Couldn't load CallLinkRecord that must exist: \(error)")
|
||||
}
|
||||
return deps.callLinkStore.fetch(rowId: callLinkRowId, tx: tx)
|
||||
.owsFailUnwrap("FOREIGN KEYs mean this must exist.")
|
||||
}()
|
||||
|
||||
if let callLinkRecord {
|
||||
@ -1236,8 +1231,8 @@ class CallsListViewController: OWSViewController, HomeTabViewController, CallSer
|
||||
} catch CallLinkManagerImpl.PeekError.expired, CallLinkManagerImpl.PeekError.invalid {
|
||||
eraId = nil
|
||||
}
|
||||
try await deps.db.awaitableWrite { tx in
|
||||
try deps.adHocCallRecordManager.handlePeekResult(eraId: eraId, rootKey: rootKey, tx: tx)
|
||||
await deps.db.awaitableWrite { tx in
|
||||
deps.adHocCallRecordManager.handlePeekResult(eraId: eraId, rootKey: rootKey, tx: tx)
|
||||
}
|
||||
}
|
||||
|
||||
@ -2051,15 +2046,9 @@ extension CallsListViewController: CallCellDelegate, NewCallViewControllerDelega
|
||||
guard let callLinkRowId else {
|
||||
return false
|
||||
}
|
||||
do {
|
||||
let callLinkRecord = try self.deps.callLinkStore.fetch(rowId: callLinkRowId, tx: tx) ?? {
|
||||
throw OWSAssertionError("Couldn't fetch CallLink that must exist.")
|
||||
}()
|
||||
return callLinkRecord.adminPasskey != nil
|
||||
} catch {
|
||||
owsFailDebug("\(error)")
|
||||
return false
|
||||
}
|
||||
let callLinkRecord = self.deps.callLinkStore.fetch(rowId: callLinkRowId, tx: tx)
|
||||
.owsFailUnwrap("FOREIGN KEYs mean this must exist.")
|
||||
return callLinkRecord.adminPasskey != nil
|
||||
}
|
||||
}
|
||||
|
||||
@ -2069,18 +2058,17 @@ extension CallsListViewController: CallCellDelegate, NewCallViewControllerDelega
|
||||
// First, delete everything that's local only. This includes thread-based
|
||||
// calls & any call link calls for which we're not the admin. These
|
||||
// deletions never fail (except for db corruption-level failures).
|
||||
callLinksToDelete = try await deps.databaseStorage.awaitableWrite { tx in
|
||||
callLinksToDelete = await deps.databaseStorage.awaitableWrite { tx in
|
||||
var callLinksToDelete = [(rootKey: CallLinkRootKey, adminPasskey: Data)]()
|
||||
var callRecordIdsWithInteractions = [CallRecord.ID]()
|
||||
for modelReferences in modelReferenceses {
|
||||
if let callLinkRowId = modelReferences.callLinkRowId {
|
||||
let callLinkRecord = try self.deps.callLinkStore.fetch(rowId: callLinkRowId, tx: tx) ?? {
|
||||
throw OWSAssertionError("Couldn't fetch CallLink that must exist.")
|
||||
}()
|
||||
let callLinkRecord = self.deps.callLinkStore.fetch(rowId: callLinkRowId, tx: tx)
|
||||
.owsFailUnwrap("FOREIGN KEYs mean this must exist.")
|
||||
if let adminPasskey = callLinkRecord.adminPasskey {
|
||||
callLinksToDelete.append((callLinkRecord.rootKey, adminPasskey))
|
||||
} else {
|
||||
try self.deleteCallRecords(forCallLinkRowId: callLinkRecord.id, tx: tx)
|
||||
self.deleteCallRecords(forCallLinkRowId: callLinkRecord.id, tx: tx)
|
||||
}
|
||||
} else {
|
||||
callRecordIdsWithInteractions.append(contentsOf: modelReferences.callRecordRowIds)
|
||||
@ -2107,8 +2095,8 @@ extension CallsListViewController: CallCellDelegate, NewCallViewControllerDelega
|
||||
try await deleteCallLinks(callLinksToDelete: callLinksToDelete)
|
||||
}
|
||||
|
||||
private nonisolated func deleteCallRecords(forCallLinkRowId callLinkRowId: Int64, tx: DBWriteTransaction) throws {
|
||||
let callRecords = try deps.callRecordStore.fetchExisting(conversationId: .callLink(callLinkRowId: callLinkRowId), limit: nil, tx: tx)
|
||||
private nonisolated func deleteCallRecords(forCallLinkRowId callLinkRowId: Int64, tx: DBWriteTransaction) {
|
||||
let callRecords = deps.callRecordStore.fetchExisting(conversationId: .callLink(callLinkRowId: callLinkRowId), limit: nil, tx: tx)
|
||||
deps.callRecordDeleteManager.deleteCallRecords(callRecords, sendSyncMessageOnDelete: true, tx: tx)
|
||||
}
|
||||
|
||||
@ -2202,13 +2190,8 @@ extension CallsListViewController: CallCellDelegate, NewCallViewControllerDelega
|
||||
|
||||
private func showCallInfo(forRootKey rootKey: CallLinkRootKey, callRecords: [CallRecord]) {
|
||||
let callLinkRecord = deps.db.read { tx -> CallLinkRecord in
|
||||
do {
|
||||
return try deps.callLinkStore.fetch(roomId: rootKey.deriveRoomId(), tx: tx) ?? {
|
||||
owsFail("Can't fetch CallLinkRecord that must exist.")
|
||||
}()
|
||||
} catch {
|
||||
owsFail("Can't fetch CallLinkRecord: \(error)")
|
||||
}
|
||||
return deps.callLinkStore.fetch(roomId: rootKey.deriveRoomId(), tx: tx)
|
||||
.owsFailUnwrap("FOREIGN KEYs mean this must exist.")
|
||||
}
|
||||
showCallInfo(viewController: CallLinkViewController.forExisting(callLinkRecord: callLinkRecord, callRecords: callRecords))
|
||||
}
|
||||
|
||||
@ -330,7 +330,7 @@ public class NotificationActionHandler {
|
||||
if let callLinkRoomId {
|
||||
return SSKEnvironment.shared.databaseStorageRef.read { tx in
|
||||
let callLinkStore = DependenciesBridge.shared.callLinkStore
|
||||
if let callLinkRecord = try? callLinkStore.fetch(roomId: callLinkRoomId, tx: tx) {
|
||||
if let callLinkRecord = callLinkStore.fetch(roomId: callLinkRoomId, tx: tx) {
|
||||
return .callLink(CallLink(rootKey: callLinkRecord.rootKey))
|
||||
}
|
||||
return nil
|
||||
|
||||
@ -66,7 +66,7 @@ final class CallsListViewControllerViewModelLoaderTest: XCTestCase {
|
||||
maxCoalescedCallsInOneViewModel: Int = 100,
|
||||
) {
|
||||
viewModelLoader = ViewModelLoader(
|
||||
callLinkStore: CallLinkRecordStoreImpl(),
|
||||
callLinkStore: CallLinkRecordStore(),
|
||||
callRecordLoader: mockCallRecordLoader,
|
||||
callViewModelForCallRecords: { self.callViewModelForCallRecords($0, $1) },
|
||||
callViewModelForUpcomingCallLink: { _, _ in owsFail("Not implemented.") },
|
||||
|
||||
@ -141,8 +141,6 @@ public class BackupArchiveAdHocCallArchiver: BackupArchiveProtoStreamWriter {
|
||||
_ adHocCall: BackupProto_AdHocCall,
|
||||
context: BackupArchive.ChatItemRestoringContext,
|
||||
) -> RestoreFrameResult {
|
||||
var partialErrors = [BackupArchive.RestoreFrameError]()
|
||||
|
||||
let callId = AdHocCallId(adHocCall: adHocCall)
|
||||
|
||||
let state: CallRecord.CallStatus.CallLinkCallStatus
|
||||
@ -169,30 +167,16 @@ public class BackupArchiveAdHocCallArchiver: BackupArchiveProtoStreamWriter {
|
||||
)
|
||||
|
||||
if let callLinkRecord = context.recipientContext[callLinkRecordId] {
|
||||
do {
|
||||
var callLinkRecord = callLinkRecord
|
||||
callLinkRecord.didInsertCallRecord()
|
||||
try callLinkRecordStore.update(callLinkRecord, tx: context.tx)
|
||||
} catch {
|
||||
partialErrors.append(
|
||||
.restoreFrameError(.databaseInsertionFailed(error)),
|
||||
)
|
||||
}
|
||||
var callLinkRecord = callLinkRecord
|
||||
callLinkRecord.didInsertCallRecord()
|
||||
callLinkRecordStore.update(callLinkRecord, tx: context.tx)
|
||||
}
|
||||
|
||||
do {
|
||||
try callRecordStore.insert(
|
||||
callRecord: adHocCallRecord,
|
||||
tx: context.tx,
|
||||
)
|
||||
} catch {
|
||||
return .failure(partialErrors + [.restoreFrameError(.databaseInsertionFailed(error))])
|
||||
}
|
||||
callRecordStore.insert(
|
||||
callRecord: adHocCallRecord,
|
||||
tx: context.tx,
|
||||
)
|
||||
|
||||
if partialErrors.isEmpty {
|
||||
return .success
|
||||
} else {
|
||||
return .partialRestore(partialErrors)
|
||||
}
|
||||
return .success
|
||||
}
|
||||
}
|
||||
|
||||
@ -237,31 +237,27 @@ final class BackupArchiveGroupCallArchiver {
|
||||
}
|
||||
|
||||
let callRecord: CallRecord
|
||||
do {
|
||||
callRecord = try groupCallRecordManager.createGroupCallRecord(
|
||||
callId: groupCall.callID,
|
||||
groupCallInteraction: groupCallInteraction,
|
||||
groupCallInteractionRowId: groupCallInteraction.sqliteRowId!,
|
||||
groupThreadRowId: chatThread.threadRowId,
|
||||
callDirection: callDirection,
|
||||
groupCallStatus: callStatus,
|
||||
groupCallRingerAci: groupCallRingerAci,
|
||||
callEventTimestamp: groupCall.startedCallTimestamp,
|
||||
shouldSendSyncMessage: false,
|
||||
callRecord = groupCallRecordManager.createGroupCallRecord(
|
||||
callId: groupCall.callID,
|
||||
groupCallInteraction: groupCallInteraction,
|
||||
groupCallInteractionRowId: groupCallInteraction.sqliteRowId!,
|
||||
groupThreadRowId: chatThread.threadRowId,
|
||||
callDirection: callDirection,
|
||||
groupCallStatus: callStatus,
|
||||
groupCallRingerAci: groupCallRingerAci,
|
||||
callEventTimestamp: groupCall.startedCallTimestamp,
|
||||
shouldSendSyncMessage: false,
|
||||
tx: context.tx,
|
||||
)
|
||||
if groupCall.hasEndedCallTimestamp {
|
||||
callRecordStore.updateCallEndedTimestamp(
|
||||
callRecord: callRecord,
|
||||
callEndedTimestamp: groupCall.endedCallTimestamp,
|
||||
tx: context.tx,
|
||||
)
|
||||
if groupCall.hasEndedCallTimestamp {
|
||||
try callRecordStore.updateCallEndedTimestamp(
|
||||
callRecord: callRecord,
|
||||
callEndedTimestamp: groupCall.endedCallTimestamp,
|
||||
tx: context.tx,
|
||||
)
|
||||
}
|
||||
if groupCall.read {
|
||||
try callRecordStore.markAsRead(callRecord: callRecord, tx: context.tx)
|
||||
}
|
||||
} catch {
|
||||
return .messageFailure([.restoreFrameError(.databaseInsertionFailed(error))])
|
||||
}
|
||||
if groupCall.read {
|
||||
callRecordStore.markAsRead(callRecord: callRecord, tx: context.tx)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -248,25 +248,21 @@ final class BackupArchiveIndividualCallArchiver {
|
||||
|
||||
if individualCall.hasCallID {
|
||||
let callRecord: CallRecord
|
||||
do {
|
||||
callRecord = try individualCallRecordManager.createRecordForInteraction(
|
||||
individualCallInteraction: individualCallInteraction,
|
||||
individualCallInteractionRowId: individualCallInteraction.sqliteRowId!,
|
||||
contactThread: contactThread,
|
||||
contactThreadRowId: chatThread.threadRowId,
|
||||
callId: individualCall.callID,
|
||||
callType: callRecordType,
|
||||
callDirection: callRecordDirection,
|
||||
individualCallStatus: callRecordStatus,
|
||||
callEventTimestamp: individualCall.startedCallTimestamp,
|
||||
shouldSendSyncMessage: false,
|
||||
tx: context.tx,
|
||||
)
|
||||
if individualCall.read {
|
||||
try callRecordStore.markAsRead(callRecord: callRecord, tx: context.tx)
|
||||
}
|
||||
} catch {
|
||||
return .messageFailure([.restoreFrameError(.databaseInsertionFailed(error))])
|
||||
callRecord = individualCallRecordManager.createRecordForInteraction(
|
||||
individualCallInteraction: individualCallInteraction,
|
||||
individualCallInteractionRowId: individualCallInteraction.sqliteRowId!,
|
||||
contactThread: contactThread,
|
||||
contactThreadRowId: chatThread.threadRowId,
|
||||
callId: individualCall.callID,
|
||||
callType: callRecordType,
|
||||
callDirection: callRecordDirection,
|
||||
individualCallStatus: callRecordStatus,
|
||||
callEventTimestamp: individualCall.startedCallTimestamp,
|
||||
shouldSendSyncMessage: false,
|
||||
tx: context.tx,
|
||||
)
|
||||
if individualCall.read {
|
||||
callRecordStore.markAsRead(callRecord: callRecord, tx: context.tx)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -7,49 +7,20 @@ import Foundation
|
||||
import GRDB
|
||||
public import SignalRingRTC
|
||||
|
||||
public protocol CallLinkRecordStore {
|
||||
func fetch(rowId: Int64, tx: DBReadTransaction) throws -> CallLinkRecord?
|
||||
func fetch(roomId: Data, tx: DBReadTransaction) throws -> CallLinkRecord?
|
||||
func insertFromBackup(
|
||||
rootKey: CallLinkRootKey,
|
||||
adminPasskey: Data?,
|
||||
name: String?,
|
||||
restrictions: CallLinkRecord.Restrictions?,
|
||||
revoked: Bool?,
|
||||
expiration: Int64?,
|
||||
isUpcoming: Bool?,
|
||||
tx: DBWriteTransaction,
|
||||
) throws -> CallLinkRecord
|
||||
func fetchOrInsert(rootKey: CallLinkRootKey, tx: DBWriteTransaction) throws -> (record: CallLinkRecord, inserted: Bool)
|
||||
|
||||
func update(_ callLinkRecord: CallLinkRecord, tx: DBWriteTransaction) throws
|
||||
func delete(_ callLinkRecord: CallLinkRecord, tx: DBWriteTransaction) throws
|
||||
|
||||
func fetchAll(tx: DBReadTransaction) throws -> [CallLinkRecord]
|
||||
func enumerateAll(tx: DBReadTransaction, block: (CallLinkRecord) throws -> Void) throws
|
||||
func fetchUpcoming(earlierThan expirationTimestamp: Date?, limit: Int, tx: DBReadTransaction) throws -> [CallLinkRecord]
|
||||
func fetchWhere(adminDeletedAtTimestampMsIsLessThan thresholdMs: UInt64, tx: DBReadTransaction) throws -> [CallLinkRecord]
|
||||
func fetchAnyPendingRecord(tx: DBReadTransaction) throws -> CallLinkRecord?
|
||||
}
|
||||
|
||||
public class CallLinkRecordStoreImpl: CallLinkRecordStore {
|
||||
public struct CallLinkRecordStore {
|
||||
public init() {}
|
||||
|
||||
public func fetch(rowId: Int64, tx: DBReadTransaction) throws -> CallLinkRecord? {
|
||||
public func fetch(rowId: Int64, tx: DBReadTransaction) -> CallLinkRecord? {
|
||||
let db = tx.database
|
||||
do {
|
||||
return failIfThrows {
|
||||
return try CallLinkRecord.fetchOne(db, key: rowId)
|
||||
} catch {
|
||||
throw error.grdbErrorForLogging
|
||||
}
|
||||
}
|
||||
|
||||
public func fetch(roomId: Data, tx: DBReadTransaction) throws -> CallLinkRecord? {
|
||||
public func fetch(roomId: Data, tx: DBReadTransaction) -> CallLinkRecord? {
|
||||
let db = tx.database
|
||||
do {
|
||||
return failIfThrows {
|
||||
return try CallLinkRecord.filter(Column(CallLinkRecord.CodingKeys.roomId) == roomId).fetchOne(db)
|
||||
} catch {
|
||||
throw error.grdbErrorForLogging
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,37 +46,46 @@ public class CallLinkRecordStoreImpl: CallLinkRecordStore {
|
||||
)
|
||||
}
|
||||
|
||||
public func fetchOrInsert(rootKey: CallLinkRootKey, tx: DBWriteTransaction) throws -> (record: CallLinkRecord, inserted: Bool) {
|
||||
if let existingRecord = try fetch(roomId: rootKey.deriveRoomId(), tx: tx) {
|
||||
public func fetchOrInsert(rootKey: CallLinkRootKey, tx: DBWriteTransaction) -> (record: CallLinkRecord, inserted: Bool) {
|
||||
if let existingRecord = fetch(roomId: rootKey.deriveRoomId(), tx: tx) {
|
||||
return (existingRecord, false)
|
||||
}
|
||||
return (try CallLinkRecord.insertRecord(rootKey: rootKey, tx: tx), true)
|
||||
return failIfThrows {
|
||||
return (
|
||||
try CallLinkRecord.insertRecord(rootKey: rootKey, tx: tx),
|
||||
true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
public func update(_ callLinkRecord: CallLinkRecord, tx: DBWriteTransaction) throws {
|
||||
public func update(_ callLinkRecord: CallLinkRecord, tx: DBWriteTransaction) {
|
||||
let db = tx.database
|
||||
do {
|
||||
failIfThrows {
|
||||
try callLinkRecord.update(db)
|
||||
} catch {
|
||||
throw error.grdbErrorForLogging
|
||||
}
|
||||
}
|
||||
|
||||
public func delete(_ callLinkRecord: CallLinkRecord, tx: DBWriteTransaction) throws {
|
||||
/// Delete the given `CallLinkRecord`, unless someone still has a reference
|
||||
/// to it.
|
||||
/// - Returns Whether or not a record was deleted.
|
||||
@discardableResult
|
||||
public func deleteIfPossible(_ callLinkRecord: CallLinkRecord, tx: DBWriteTransaction) -> Bool {
|
||||
let db = tx.database
|
||||
do {
|
||||
try callLinkRecord.delete(db)
|
||||
} catch {
|
||||
throw error.grdbErrorForLogging
|
||||
return failIfThrows {
|
||||
do {
|
||||
try callLinkRecord.delete(db)
|
||||
return true
|
||||
} catch DatabaseError.SQLITE_CONSTRAINT {
|
||||
// We'll delete it later -- something else is still using it.
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func fetchAll(tx: DBReadTransaction) throws -> [CallLinkRecord] {
|
||||
public func fetchAll(tx: DBReadTransaction) -> [CallLinkRecord] {
|
||||
let db = tx.database
|
||||
do {
|
||||
return failIfThrows {
|
||||
return try CallLinkRecord.fetchAll(db)
|
||||
} catch {
|
||||
throw error.grdbErrorForLogging
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,9 +100,9 @@ public class CallLinkRecordStoreImpl: CallLinkRecordStore {
|
||||
}
|
||||
}
|
||||
|
||||
public func fetchUpcoming(earlierThan expirationTimestamp: Date?, limit: Int, tx: DBReadTransaction) throws -> [CallLinkRecord] {
|
||||
public func fetchUpcoming(earlierThan expirationTimestamp: Date?, limit: Int, tx: DBReadTransaction) -> [CallLinkRecord] {
|
||||
let db = tx.database
|
||||
do {
|
||||
return failIfThrows {
|
||||
let isUpcomingColumn = Column(CallLinkRecord.CodingKeys.isUpcoming)
|
||||
let expirationColumn = Column(CallLinkRecord.CodingKeys.expiration)
|
||||
|
||||
@ -131,44 +111,20 @@ public class CallLinkRecordStoreImpl: CallLinkRecordStore {
|
||||
baseQuery = baseQuery.filter(expirationColumn < expirationTimestamp)
|
||||
}
|
||||
return try baseQuery.fetchAll(db)
|
||||
} catch {
|
||||
throw error.grdbErrorForLogging
|
||||
}
|
||||
}
|
||||
|
||||
public func fetchWhere(adminDeletedAtTimestampMsIsLessThan thresholdMs: UInt64, tx: DBReadTransaction) throws -> [CallLinkRecord] {
|
||||
public func fetchWhere(adminDeletedAtTimestampMsIsLessThan thresholdMs: UInt64, tx: DBReadTransaction) -> [CallLinkRecord] {
|
||||
let db = tx.database
|
||||
do {
|
||||
return failIfThrows {
|
||||
return try CallLinkRecord.filter(Column(CallLinkRecord.CodingKeys.adminDeletedAtTimestampMs) < Int64(bitPattern: thresholdMs)).fetchAll(db)
|
||||
} catch {
|
||||
throw error.grdbErrorForLogging
|
||||
}
|
||||
}
|
||||
|
||||
public func fetchAnyPendingRecord(tx: DBReadTransaction) throws -> CallLinkRecord? {
|
||||
public func fetchAnyPendingRecord(tx: DBReadTransaction) -> CallLinkRecord? {
|
||||
let db = tx.database
|
||||
do {
|
||||
return failIfThrows {
|
||||
return try CallLinkRecord.filter(Column(CallLinkRecord.CodingKeys.pendingFetchCounter) > 0).fetchOne(db)
|
||||
} catch {
|
||||
throw error.grdbErrorForLogging
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if TESTABLE_BUILD
|
||||
|
||||
final class MockCallLinkRecordStore: CallLinkRecordStore {
|
||||
func fetch(rowId: Int64, tx: DBReadTransaction) throws -> CallLinkRecord? { fatalError() }
|
||||
func fetch(roomId: Data, tx: DBReadTransaction) throws -> CallLinkRecord? { fatalError() }
|
||||
func insertFromBackup(rootKey: CallLinkRootKey, adminPasskey: Data?, name: String?, restrictions: CallLinkRecord.Restrictions?, revoked: Bool?, expiration: Int64?, isUpcoming: Bool?, tx: DBWriteTransaction) throws -> CallLinkRecord { fatalError() }
|
||||
func fetchOrInsert(rootKey: CallLinkRootKey, tx: DBWriteTransaction) throws -> (record: CallLinkRecord, inserted: Bool) { fatalError() }
|
||||
func update(_ callLinkRecord: CallLinkRecord, tx: DBWriteTransaction) throws { fatalError() }
|
||||
func delete(_ callLinkRecord: CallLinkRecord, tx: DBWriteTransaction) throws { fatalError() }
|
||||
func fetchAll(tx: DBReadTransaction) throws -> [CallLinkRecord] { fatalError() }
|
||||
func enumerateAll(tx: DBReadTransaction, block: (CallLinkRecord) throws -> Void) throws { fatalError() }
|
||||
func fetchUpcoming(earlierThan expirationTimestamp: Date?, limit: Int, tx: DBReadTransaction) throws -> [CallLinkRecord] { fatalError() }
|
||||
func fetchWhere(adminDeletedAtTimestampMsIsLessThan thresholdMs: UInt64, tx: DBReadTransaction) throws -> [CallLinkRecord] { fatalError() }
|
||||
func fetchAnyPendingRecord(tx: DBReadTransaction) throws -> CallLinkRecord? { fatalError() }
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -14,23 +14,23 @@ public protocol AdHocCallRecordManager {
|
||||
timestamp: UInt64,
|
||||
shouldSendSyncMessge: Bool,
|
||||
tx: DBWriteTransaction,
|
||||
) throws
|
||||
)
|
||||
|
||||
func handlePeekResult(
|
||||
eraId: String?,
|
||||
rootKey: CallLinkRootKey,
|
||||
tx: DBWriteTransaction,
|
||||
) throws
|
||||
)
|
||||
}
|
||||
|
||||
final class AdHocCallRecordManagerImpl: AdHocCallRecordManager {
|
||||
private let callRecordStore: any CallRecordStore
|
||||
private let callLinkStore: any CallLinkRecordStore
|
||||
private let callLinkStore: CallLinkRecordStore
|
||||
private let outgoingSyncMessageManager: any OutgoingCallEventSyncMessageManager
|
||||
|
||||
init(
|
||||
callRecordStore: any CallRecordStore,
|
||||
callLinkStore: any CallLinkRecordStore,
|
||||
callLinkStore: CallLinkRecordStore,
|
||||
outgoingSyncMessageManager: any OutgoingCallEventSyncMessageManager,
|
||||
) {
|
||||
self.callRecordStore = callRecordStore
|
||||
@ -45,7 +45,7 @@ final class AdHocCallRecordManagerImpl: AdHocCallRecordManager {
|
||||
timestamp: UInt64,
|
||||
shouldSendSyncMessge: Bool,
|
||||
tx: DBWriteTransaction,
|
||||
) throws {
|
||||
) {
|
||||
// This shouldn't happen (we block joining earlier), but race conditions
|
||||
// theoretically allow it, and this is the final point at which we can
|
||||
// enforce the invariant that deleted links can't have call records.
|
||||
@ -71,14 +71,10 @@ final class AdHocCallRecordManagerImpl: AdHocCallRecordManager {
|
||||
callStatus: status,
|
||||
callBeganTimestamp: timestamp,
|
||||
)
|
||||
do {
|
||||
try callRecordStore.insert(callRecord: callRecord, tx: tx)
|
||||
} catch let error {
|
||||
owsFailBeta("Failed to insert call record: \(error)")
|
||||
}
|
||||
callRecordStore.insert(callRecord: callRecord, tx: tx)
|
||||
var callLink = callLink
|
||||
callLink.didInsertCallRecord()
|
||||
try callLinkStore.update(callLink, tx: tx)
|
||||
callLinkStore.update(callLink, tx: tx)
|
||||
|
||||
case .matchFound(let callRecord2):
|
||||
callRecord = callRecord2
|
||||
@ -106,24 +102,24 @@ final class AdHocCallRecordManagerImpl: AdHocCallRecordManager {
|
||||
eraId: String?,
|
||||
rootKey: CallLinkRootKey,
|
||||
tx: DBWriteTransaction,
|
||||
) throws {
|
||||
guard var callLinkRecord = try self.callLinkStore.fetch(roomId: rootKey.deriveRoomId(), tx: tx) else {
|
||||
) {
|
||||
guard var callLinkRecord = self.callLinkStore.fetch(roomId: rootKey.deriveRoomId(), tx: tx) else {
|
||||
return
|
||||
}
|
||||
let callId = eraId.map(callIdFromEra(_:))
|
||||
if callLinkRecord.activeCallId != callId {
|
||||
callLinkRecord.activeCallId = callId
|
||||
try self.callLinkStore.update(callLinkRecord, tx: tx)
|
||||
self.callLinkStore.update(callLinkRecord, tx: tx)
|
||||
}
|
||||
if let callId {
|
||||
// Things that are already in the calls tab get updated timestamps (and
|
||||
// move to the top) whenever we notice that they're active. "Already in the
|
||||
// calls tab" means "isUpcoming or hasCallRecord".
|
||||
let shouldObserveResult = try { () -> Bool in
|
||||
let shouldObserveResult = { () -> Bool in
|
||||
if callLinkRecord.isUpcoming == true {
|
||||
return true
|
||||
}
|
||||
let callRecords = try self.callRecordStore.fetchExisting(
|
||||
let callRecords = self.callRecordStore.fetchExisting(
|
||||
conversationId: .callLink(callLinkRowId: callLinkRecord.id),
|
||||
limit: 1,
|
||||
tx: tx,
|
||||
@ -131,7 +127,7 @@ final class AdHocCallRecordManagerImpl: AdHocCallRecordManager {
|
||||
return !callRecords.isEmpty
|
||||
}()
|
||||
if shouldObserveResult {
|
||||
try self.createOrUpdateRecord(
|
||||
self.createOrUpdateRecord(
|
||||
callId: callId,
|
||||
callLink: callLinkRecord,
|
||||
status: .generic,
|
||||
@ -147,11 +143,11 @@ final class AdHocCallRecordManagerImpl: AdHocCallRecordManager {
|
||||
#if TESTABLE_BUILD
|
||||
|
||||
final class MockAdHocCallRecordManager: AdHocCallRecordManager {
|
||||
func createOrUpdateRecord(callId: UInt64, callLink: CallLinkRecord, status: CallRecord.CallStatus.CallLinkCallStatus, timestamp: UInt64, shouldSendSyncMessge: Bool, tx: DBWriteTransaction) throws {
|
||||
func createOrUpdateRecord(callId: UInt64, callLink: CallLinkRecord, status: CallRecord.CallStatus.CallLinkCallStatus, timestamp: UInt64, shouldSendSyncMessge: Bool, tx: DBWriteTransaction) {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
func handlePeekResult(eraId: String?, rootKey: CallLinkRootKey, tx: DBWriteTransaction) throws {
|
||||
func handlePeekResult(eraId: String?, rootKey: CallLinkRootKey, tx: DBWriteTransaction) {
|
||||
fatalError()
|
||||
}
|
||||
}
|
||||
|
||||
@ -196,14 +196,10 @@ class CallRecordMissedCallManagerImpl: CallRecordMissedCallManager {
|
||||
while let unreadCallRecord = try unreadCallCursor.next() {
|
||||
markedAsReadCount += 1
|
||||
|
||||
do {
|
||||
try callRecordStore.markAsRead(
|
||||
callRecord: unreadCallRecord,
|
||||
tx: tx,
|
||||
)
|
||||
} catch let error {
|
||||
owsFailBeta("Failed to update call record: \(error)")
|
||||
}
|
||||
callRecordStore.markAsRead(
|
||||
callRecord: unreadCallRecord,
|
||||
tx: tx,
|
||||
)
|
||||
}
|
||||
|
||||
owsAssertDebug(
|
||||
|
||||
@ -36,7 +36,7 @@ public protocol CallRecordStore {
|
||||
/// Insert the given call record.
|
||||
/// - Important
|
||||
/// Posts an `.inserted` ``CallRecordStoreNotification``.
|
||||
func insert(callRecord: CallRecord, tx: DBWriteTransaction) throws
|
||||
func insert(callRecord: CallRecord, tx: DBWriteTransaction)
|
||||
|
||||
/// Deletes the given call records and creates ``DeletedCallRecord``s
|
||||
/// in their place.
|
||||
@ -81,7 +81,7 @@ public protocol CallRecordStore {
|
||||
func markAsRead(
|
||||
callRecord: CallRecord,
|
||||
tx: DBWriteTransaction,
|
||||
) throws
|
||||
)
|
||||
|
||||
/// Update the direction of the given call record.
|
||||
func updateDirection(
|
||||
@ -112,7 +112,7 @@ public protocol CallRecordStore {
|
||||
callRecord: CallRecord,
|
||||
callEndedTimestamp: UInt64,
|
||||
tx: DBWriteTransaction,
|
||||
) throws
|
||||
)
|
||||
|
||||
/// Update all relevant records in response to a thread merge.
|
||||
/// - Parameter fromThreadRowId
|
||||
@ -143,7 +143,7 @@ public protocol CallRecordStore {
|
||||
conversationId: CallRecord.ConversationID,
|
||||
limit: Int?,
|
||||
tx: DBReadTransaction,
|
||||
) throws -> [CallRecord]
|
||||
) -> [CallRecord]
|
||||
|
||||
/// Fetch the record referencing the given ``TSInteraction`` SQLite row ID,
|
||||
/// if one exists.
|
||||
@ -168,15 +168,13 @@ class CallRecordStoreImpl: CallRecordStore {
|
||||
|
||||
// MARK: - Protocol methods
|
||||
|
||||
func insert(callRecord: CallRecord, tx: DBWriteTransaction) throws {
|
||||
let insertResult = Result<Void, Error>(catching: { try _insert(callRecord: callRecord, tx: tx) })
|
||||
func insert(callRecord: CallRecord, tx: DBWriteTransaction) {
|
||||
_insert(callRecord: callRecord, tx: tx)
|
||||
|
||||
postNotification(
|
||||
updateType: .inserted,
|
||||
tx: tx,
|
||||
)
|
||||
|
||||
try insertResult.get()
|
||||
}
|
||||
|
||||
private var deletedCallRecordIds = [CallRecord.ID]()
|
||||
@ -211,9 +209,11 @@ class CallRecordStoreImpl: CallRecordStore {
|
||||
)
|
||||
}
|
||||
|
||||
func markAsRead(callRecord: CallRecord, tx: DBWriteTransaction) throws {
|
||||
func markAsRead(callRecord: CallRecord, tx: DBWriteTransaction) {
|
||||
callRecord.unreadStatus = .read
|
||||
try callRecord.update(tx.database)
|
||||
failIfThrows {
|
||||
try callRecord.update(tx.database)
|
||||
}
|
||||
}
|
||||
|
||||
func updateDirection(
|
||||
@ -222,10 +222,8 @@ class CallRecordStoreImpl: CallRecordStore {
|
||||
tx: DBWriteTransaction,
|
||||
) {
|
||||
callRecord.callDirection = newCallDirection
|
||||
do {
|
||||
failIfThrows {
|
||||
try callRecord.update(tx.database)
|
||||
} catch let error {
|
||||
owsFailBeta("Failed to update call record: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
@ -235,10 +233,8 @@ class CallRecordStoreImpl: CallRecordStore {
|
||||
tx: DBWriteTransaction,
|
||||
) {
|
||||
callRecord.setGroupCallRingerAci(newGroupCallRingerAci)
|
||||
do {
|
||||
failIfThrows {
|
||||
try callRecord.update(tx.database)
|
||||
} catch let error {
|
||||
owsFailBeta("Failed to update call record: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
@ -248,10 +244,8 @@ class CallRecordStoreImpl: CallRecordStore {
|
||||
tx: DBWriteTransaction,
|
||||
) {
|
||||
callRecord.callBeganTimestamp = callBeganTimestamp
|
||||
do {
|
||||
failIfThrows {
|
||||
try callRecord.update(tx.database)
|
||||
} catch let error {
|
||||
owsFailBeta("Failed to update call record: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
@ -259,9 +253,11 @@ class CallRecordStoreImpl: CallRecordStore {
|
||||
callRecord: CallRecord,
|
||||
callEndedTimestamp: UInt64,
|
||||
tx: DBWriteTransaction,
|
||||
) throws {
|
||||
) {
|
||||
callRecord.callEndedTimestamp = callEndedTimestamp
|
||||
try callRecord.update(tx.database)
|
||||
failIfThrows {
|
||||
try callRecord.update(tx.database)
|
||||
}
|
||||
}
|
||||
|
||||
func updateWithMergedThread(
|
||||
@ -299,12 +295,12 @@ class CallRecordStoreImpl: CallRecordStore {
|
||||
conversationId: CallRecord.ConversationID,
|
||||
limit: Int?,
|
||||
tx: DBReadTransaction,
|
||||
) throws -> [CallRecord] {
|
||||
) -> [CallRecord] {
|
||||
switch conversationId {
|
||||
case .thread(let threadRowId):
|
||||
return try fetchAll(columnArgs: [(.threadRowId, threadRowId)], limit: limit, tx: tx)
|
||||
return fetchAll(columnArgs: [(.threadRowId, threadRowId)], limit: limit, tx: tx)
|
||||
case .callLink(let callLinkRowId):
|
||||
return try fetchAll(columnArgs: [(.callLinkRowId, callLinkRowId)], limit: limit, tx: tx)
|
||||
return fetchAll(columnArgs: [(.callLinkRowId, callLinkRowId)], limit: limit, tx: tx)
|
||||
}
|
||||
}
|
||||
|
||||
@ -330,21 +326,21 @@ class CallRecordStoreImpl: CallRecordStore {
|
||||
|
||||
// MARK: - Mutations (impl)
|
||||
|
||||
func _insert(callRecord: CallRecord, tx: DBWriteTransaction) throws {
|
||||
try callRecord.insert(tx.database)
|
||||
private func _insert(callRecord: CallRecord, tx: DBWriteTransaction) {
|
||||
failIfThrows {
|
||||
try callRecord.insert(tx.database)
|
||||
}
|
||||
}
|
||||
|
||||
func _delete(callRecords: [CallRecord], tx: DBWriteTransaction) {
|
||||
private func _delete(callRecords: [CallRecord], tx: DBWriteTransaction) {
|
||||
for callRecord in callRecords {
|
||||
do {
|
||||
failIfThrows {
|
||||
try callRecord.delete(tx.database)
|
||||
} catch let error {
|
||||
owsFailBeta("Failed to delete call record: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func _updateCallAndUnreadStatus(
|
||||
private func _updateCallAndUnreadStatus(
|
||||
callRecord: CallRecord,
|
||||
newCallStatus: CallRecord.CallStatus,
|
||||
tx: DBWriteTransaction,
|
||||
@ -354,16 +350,14 @@ class CallRecordStoreImpl: CallRecordStore {
|
||||
|
||||
callRecord.callStatus = newCallStatus
|
||||
callRecord.unreadStatus = CallRecord.CallUnreadStatus(callStatus: newCallStatus)
|
||||
do {
|
||||
failIfThrows {
|
||||
try callRecord.update(tx.database)
|
||||
} catch let error {
|
||||
owsFailBeta("Failed to update call record: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Queries (impl)
|
||||
|
||||
func _fetch(
|
||||
private func _fetch(
|
||||
callId: UInt64,
|
||||
conversationId: CallRecord.ConversationID,
|
||||
tx: DBReadTransaction,
|
||||
@ -394,31 +388,23 @@ class CallRecordStoreImpl: CallRecordStore {
|
||||
columnArgs: [(CallRecord.CodingKeys, DatabaseValueConvertible)],
|
||||
tx: DBReadTransaction,
|
||||
) -> CallRecord? {
|
||||
do {
|
||||
let results = try fetchAll(columnArgs: columnArgs, limit: nil, tx: tx)
|
||||
owsAssertDebug(results.count <= 1, "columnArgs must identify a unique row")
|
||||
return results.first
|
||||
} catch {
|
||||
let columns = columnArgs.map { column, _ in column }
|
||||
owsFailBeta("Error fetching CallRecord by \(columns): \(error)")
|
||||
return nil
|
||||
}
|
||||
let results = fetchAll(columnArgs: columnArgs, limit: nil, tx: tx)
|
||||
owsAssertDebug(results.count <= 1, "columnArgs must identify a unique row")
|
||||
return results.first
|
||||
}
|
||||
|
||||
fileprivate func fetchAll(
|
||||
columnArgs: [(CallRecord.CodingKeys, DatabaseValueConvertible)],
|
||||
limit: Int?,
|
||||
tx: DBReadTransaction,
|
||||
) throws -> [CallRecord] {
|
||||
) -> [CallRecord] {
|
||||
let (sqlString, sqlArgs) = compileQuery(columnArgs: columnArgs, limit: limit)
|
||||
|
||||
do {
|
||||
return failIfThrows {
|
||||
return try CallRecord.fetchAll(tx.database, SQLRequest(
|
||||
sql: sqlString,
|
||||
arguments: StatementArguments(sqlArgs),
|
||||
))
|
||||
} catch {
|
||||
throw error.grdbErrorForLogging
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -12,7 +12,7 @@ public protocol CallRecordSyncMessageConversationIdAdapter {
|
||||
conversationId: Data,
|
||||
callId: UInt64,
|
||||
tx: DBReadTransaction,
|
||||
) throws -> CallRecord?
|
||||
) -> CallRecord?
|
||||
|
||||
/// Generates a conversation ID for use in call-related sync messages, from
|
||||
/// a ``CallRecord``.
|
||||
@ -24,13 +24,13 @@ public protocol CallRecordSyncMessageConversationIdAdapter {
|
||||
|
||||
class CallRecordSyncMessageConversationIdAdapterImpl: CallRecordSyncMessageConversationIdAdapter {
|
||||
|
||||
private let callLinkStore: any CallLinkRecordStore
|
||||
private let callLinkStore: CallLinkRecordStore
|
||||
private let callRecordStore: CallRecordStore
|
||||
private let recipientDatabaseTable: RecipientDatabaseTable
|
||||
private let threadStore: ThreadStore
|
||||
|
||||
init(
|
||||
callLinkStore: any CallLinkRecordStore,
|
||||
callLinkStore: CallLinkRecordStore,
|
||||
callRecordStore: CallRecordStore,
|
||||
recipientDatabaseTable: RecipientDatabaseTable,
|
||||
threadStore: ThreadStore,
|
||||
@ -47,13 +47,13 @@ class CallRecordSyncMessageConversationIdAdapterImpl: CallRecordSyncMessageConve
|
||||
conversationId: Data,
|
||||
callId: UInt64,
|
||||
tx: DBReadTransaction,
|
||||
) throws -> CallRecord? {
|
||||
return try parse(conversationId: conversationId, tx: tx).flatMap {
|
||||
) -> CallRecord? {
|
||||
return parse(conversationId: conversationId, tx: tx).flatMap {
|
||||
return callRecordStore.fetch(callId: callId, conversationId: $0, tx: tx).unwrapped
|
||||
}
|
||||
}
|
||||
|
||||
private func parse(conversationId: Data, tx: DBReadTransaction) throws -> CallRecord.ConversationID? {
|
||||
private func parse(conversationId: Data, tx: DBReadTransaction) -> CallRecord.ConversationID? {
|
||||
if let serviceId = try? ServiceId.parseFrom(serviceIdBinary: conversationId) {
|
||||
guard
|
||||
let recipient = recipientDatabaseTable.fetchRecipient(serviceId: serviceId, transaction: tx),
|
||||
@ -69,7 +69,7 @@ class CallRecordSyncMessageConversationIdAdapterImpl: CallRecordSyncMessageConve
|
||||
{
|
||||
return .thread(threadRowId: groupThread.sqliteRowId!)
|
||||
}
|
||||
if let callLinkRecord = try callLinkStore.fetch(roomId: conversationId, tx: tx) {
|
||||
if let callLinkRecord = callLinkStore.fetch(roomId: conversationId, tx: tx) {
|
||||
return .callLink(callLinkRowId: callLinkRecord.id)
|
||||
}
|
||||
return nil
|
||||
@ -93,7 +93,7 @@ class CallRecordSyncMessageConversationIdAdapterImpl: CallRecordSyncMessageConve
|
||||
throw OWSAssertionError("Unexpected thread type for call record!")
|
||||
}
|
||||
case .callLink(let callLinkRowId):
|
||||
guard let callLinkRecord = try callLinkStore.fetch(rowId: callLinkRowId, tx: tx) else {
|
||||
guard let callLinkRecord = callLinkStore.fetch(rowId: callLinkRowId, tx: tx) else {
|
||||
throw OWSAssertionError("Missing CallLinkRecord - how did we get here?")
|
||||
}
|
||||
return callLinkRecord.roomId
|
||||
|
||||
@ -16,7 +16,7 @@ public protocol GroupCallRecordManager {
|
||||
callEventTimestamp: UInt64,
|
||||
shouldSendSyncMessage: Bool,
|
||||
tx: DBWriteTransaction,
|
||||
) throws
|
||||
)
|
||||
|
||||
/// Create a group call record with the given parameters.
|
||||
///
|
||||
@ -35,7 +35,7 @@ public protocol GroupCallRecordManager {
|
||||
callEventTimestamp: UInt64,
|
||||
shouldSendSyncMessage: Bool,
|
||||
tx: DBWriteTransaction,
|
||||
) throws -> CallRecord
|
||||
) -> CallRecord
|
||||
|
||||
/// Update an group existing call record with the given parameters.
|
||||
///
|
||||
@ -81,8 +81,8 @@ public extension GroupCallRecordManager {
|
||||
groupCallInteractionRowId: Int64,
|
||||
groupThreadRowId: Int64,
|
||||
tx: DBWriteTransaction,
|
||||
) throws -> CallRecord {
|
||||
try createGroupCallRecord(
|
||||
) -> CallRecord {
|
||||
createGroupCallRecord(
|
||||
callId: callId,
|
||||
groupCallInteraction: groupCallInteraction,
|
||||
groupCallInteractionRowId: groupCallInteractionRowId,
|
||||
@ -125,7 +125,7 @@ public class GroupCallRecordManagerImpl: GroupCallRecordManager {
|
||||
callEventTimestamp: UInt64,
|
||||
shouldSendSyncMessage: Bool,
|
||||
tx: DBWriteTransaction,
|
||||
) throws {
|
||||
) {
|
||||
// We never have a group call ringer in this flow.
|
||||
let groupCallRingerAci: Aci? = nil
|
||||
|
||||
@ -153,7 +153,7 @@ public class GroupCallRecordManagerImpl: GroupCallRecordManager {
|
||||
tx: tx,
|
||||
)
|
||||
|
||||
_ = try createGroupCallRecord(
|
||||
_ = createGroupCallRecord(
|
||||
callId: callId,
|
||||
groupCallInteraction: newGroupCallInteraction,
|
||||
groupCallInteractionRowId: interactionRowId,
|
||||
@ -179,7 +179,7 @@ public class GroupCallRecordManagerImpl: GroupCallRecordManager {
|
||||
callEventTimestamp: UInt64,
|
||||
shouldSendSyncMessage: Bool,
|
||||
tx: DBWriteTransaction,
|
||||
) throws -> CallRecord {
|
||||
) -> CallRecord {
|
||||
let newCallRecord = CallRecord(
|
||||
callId: callId,
|
||||
interactionRowId: groupCallInteractionRowId,
|
||||
@ -191,7 +191,7 @@ public class GroupCallRecordManagerImpl: GroupCallRecordManager {
|
||||
callBeganTimestamp: callEventTimestamp,
|
||||
)
|
||||
|
||||
let insertResult = Result(catching: { try callRecordStore.insert(callRecord: newCallRecord, tx: tx) })
|
||||
callRecordStore.insert(callRecord: newCallRecord, tx: tx)
|
||||
|
||||
if shouldSendSyncMessage {
|
||||
outgoingSyncMessageManager.sendSyncMessage(
|
||||
@ -202,8 +202,6 @@ public class GroupCallRecordManagerImpl: GroupCallRecordManager {
|
||||
)
|
||||
}
|
||||
|
||||
try insertResult.get()
|
||||
|
||||
return newCallRecord
|
||||
}
|
||||
|
||||
|
||||
@ -203,22 +203,18 @@ public final class GroupCallRecordRingUpdateHandler: GroupCallRecordRingUpdateDe
|
||||
)
|
||||
|
||||
ringUpdateLogger.info("Creating group call record for ring update.")
|
||||
do {
|
||||
_ = try groupCallRecordManager.createGroupCallRecord(
|
||||
callId: callId,
|
||||
groupCallInteraction: newGroupCallInteraction,
|
||||
groupCallInteractionRowId: interactionRowId,
|
||||
groupThreadRowId: groupThreadRowId,
|
||||
callDirection: .incoming,
|
||||
groupCallStatus: groupCallStatus,
|
||||
groupCallRingerAci: ringerAci,
|
||||
callEventTimestamp: callEventTimestamp,
|
||||
shouldSendSyncMessage: false,
|
||||
tx: tx,
|
||||
)
|
||||
} catch let error {
|
||||
owsFailBeta("Failed to insert call record: \(error)")
|
||||
}
|
||||
_ = groupCallRecordManager.createGroupCallRecord(
|
||||
callId: callId,
|
||||
groupCallInteraction: newGroupCallInteraction,
|
||||
groupCallInteractionRowId: interactionRowId,
|
||||
groupThreadRowId: groupThreadRowId,
|
||||
callDirection: .incoming,
|
||||
groupCallStatus: groupCallStatus,
|
||||
groupCallRingerAci: ringerAci,
|
||||
callEventTimestamp: callEventTimestamp,
|
||||
shouldSendSyncMessage: false,
|
||||
tx: tx,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,7 +18,7 @@ protocol IncomingCallEventSyncMessageManager {
|
||||
|
||||
final class IncomingCallEventSyncMessageManagerImpl: IncomingCallEventSyncMessageManager {
|
||||
private let adHocCallRecordManager: any AdHocCallRecordManager
|
||||
private let callLinkStore: any CallLinkRecordStore
|
||||
private let callLinkStore: CallLinkRecordStore
|
||||
private let callRecordStore: CallRecordStore
|
||||
private let callRecordDeleteManager: CallRecordDeleteManager
|
||||
private let groupCallRecordManager: GroupCallRecordManager
|
||||
@ -31,7 +31,7 @@ final class IncomingCallEventSyncMessageManagerImpl: IncomingCallEventSyncMessag
|
||||
|
||||
init(
|
||||
adHocCallRecordManager: any AdHocCallRecordManager,
|
||||
callLinkStore: any CallLinkRecordStore,
|
||||
callLinkStore: CallLinkRecordStore,
|
||||
callRecordStore: CallRecordStore,
|
||||
callRecordDeleteManager: CallRecordDeleteManager,
|
||||
groupCallRecordManager: GroupCallRecordManager,
|
||||
@ -315,7 +315,7 @@ final class IncomingCallEventSyncMessageManagerImpl: IncomingCallEventSyncMessag
|
||||
}
|
||||
|
||||
case .adHoc(let roomId):
|
||||
guard let callLinkRecord = callLinkRecord(forRoomId: roomId, tx: tx) else {
|
||||
guard let callLinkRecord = callLinkStore.fetch(roomId: roomId, tx: tx) else {
|
||||
logger.error("Missing call link record for incoming call event sync message!")
|
||||
return
|
||||
}
|
||||
@ -340,28 +340,14 @@ final class IncomingCallEventSyncMessageManagerImpl: IncomingCallEventSyncMessag
|
||||
newStatus = .generic
|
||||
}
|
||||
|
||||
do {
|
||||
try adHocCallRecordManager.createOrUpdateRecord(
|
||||
callId: callId,
|
||||
callLink: callLinkRecord,
|
||||
status: newStatus,
|
||||
timestamp: callTimestamp,
|
||||
shouldSendSyncMessge: false,
|
||||
tx: tx,
|
||||
)
|
||||
} catch {
|
||||
owsFailDebug("\(error)")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func callLinkRecord(forRoomId roomId: Data, tx: DBReadTransaction) -> CallLinkRecord? {
|
||||
do {
|
||||
return try callLinkStore.fetch(roomId: roomId, tx: tx)
|
||||
} catch {
|
||||
CallRecordLogger.shared.error("Couldn't fetch CallLinkRecord: \(error)")
|
||||
return nil
|
||||
adHocCallRecordManager.createOrUpdateRecord(
|
||||
callId: callId,
|
||||
callLink: callLinkRecord,
|
||||
status: newStatus,
|
||||
timestamp: callTimestamp,
|
||||
shouldSendSyncMessge: false,
|
||||
tx: tx,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -469,24 +455,20 @@ private extension IncomingCallEventSyncMessageManagerImpl {
|
||||
owsFail("Missing SQLite row ID for just-inserted interaction!")
|
||||
}
|
||||
|
||||
do {
|
||||
_ = try individualCallRecordManager.createRecordForInteraction(
|
||||
individualCallInteraction: newIndividualCallInteraction,
|
||||
individualCallInteractionRowId: interactionRowId,
|
||||
contactThread: contactThread,
|
||||
contactThreadRowId: contactThreadRowId,
|
||||
callId: callId,
|
||||
callType: callType,
|
||||
callDirection: callDirection,
|
||||
individualCallStatus: individualCallStatus,
|
||||
// The interaction's timestamp is the call event's timestamp.
|
||||
callEventTimestamp: newIndividualCallInteraction.timestamp,
|
||||
shouldSendSyncMessage: false,
|
||||
tx: tx,
|
||||
)
|
||||
} catch let error {
|
||||
owsFailBeta("Failed to insert call record: \(error)")
|
||||
}
|
||||
_ = individualCallRecordManager.createRecordForInteraction(
|
||||
individualCallInteraction: newIndividualCallInteraction,
|
||||
individualCallInteractionRowId: interactionRowId,
|
||||
contactThread: contactThread,
|
||||
contactThreadRowId: contactThreadRowId,
|
||||
callId: callId,
|
||||
callType: callType,
|
||||
callDirection: callDirection,
|
||||
individualCallStatus: individualCallStatus,
|
||||
// The interaction's timestamp is the call event's timestamp.
|
||||
callEventTimestamp: newIndividualCallInteraction.timestamp,
|
||||
shouldSendSyncMessage: false,
|
||||
tx: tx,
|
||||
)
|
||||
|
||||
markThingsAsReadForIncomingSyncMessage(
|
||||
callInteraction: newIndividualCallInteraction,
|
||||
@ -544,22 +526,18 @@ private extension IncomingCallEventSyncMessageManagerImpl {
|
||||
tx: tx,
|
||||
)
|
||||
|
||||
do {
|
||||
_ = try groupCallRecordManager.createGroupCallRecord(
|
||||
callId: callId,
|
||||
groupCallInteraction: newGroupCallInteraction,
|
||||
groupCallInteractionRowId: interactionRowId,
|
||||
groupThreadRowId: groupThreadRowId,
|
||||
callDirection: callDirection,
|
||||
groupCallStatus: groupCallStatus,
|
||||
groupCallRingerAci: nil,
|
||||
callEventTimestamp: callEventTimestamp,
|
||||
shouldSendSyncMessage: false,
|
||||
tx: tx,
|
||||
)
|
||||
} catch let error {
|
||||
owsFailBeta("Failed to insert call record: \(error)")
|
||||
}
|
||||
_ = groupCallRecordManager.createGroupCallRecord(
|
||||
callId: callId,
|
||||
groupCallInteraction: newGroupCallInteraction,
|
||||
groupCallInteractionRowId: interactionRowId,
|
||||
groupThreadRowId: groupThreadRowId,
|
||||
callDirection: callDirection,
|
||||
groupCallStatus: groupCallStatus,
|
||||
groupCallRingerAci: nil,
|
||||
callEventTimestamp: callEventTimestamp,
|
||||
shouldSendSyncMessage: false,
|
||||
tx: tx,
|
||||
)
|
||||
|
||||
markThingsAsReadForIncomingSyncMessage(
|
||||
callInteraction: newGroupCallInteraction,
|
||||
|
||||
@ -41,15 +41,11 @@ class IncomingCallLogEventSyncMessageManagerImpl: IncomingCallLogEventSyncMessag
|
||||
/// 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 callRecordConversationIdAdapter.hydrate(
|
||||
conversationId: callIdentifiers.conversationId,
|
||||
callId: callIdentifiers.callId,
|
||||
tx: tx,
|
||||
)
|
||||
}
|
||||
return nil
|
||||
}()
|
||||
|
||||
@ -24,7 +24,7 @@ public protocol IndividualCallRecordManager {
|
||||
contactThreadRowId: Int64,
|
||||
callId: UInt64,
|
||||
tx: DBWriteTransaction,
|
||||
) throws
|
||||
)
|
||||
|
||||
/// Create a call record for the given interaction's current state.
|
||||
func createRecordForInteraction(
|
||||
@ -39,7 +39,7 @@ public protocol IndividualCallRecordManager {
|
||||
callEventTimestamp: UInt64,
|
||||
shouldSendSyncMessage: Bool,
|
||||
tx: DBWriteTransaction,
|
||||
) throws -> CallRecord
|
||||
) -> CallRecord
|
||||
|
||||
/// Update the given call record.
|
||||
func updateRecord(
|
||||
@ -121,7 +121,7 @@ public class IndividualCallRecordManagerImpl: IndividualCallRecordManager {
|
||||
contactThreadRowId: Int64,
|
||||
callId: UInt64,
|
||||
tx: DBWriteTransaction,
|
||||
) throws {
|
||||
) {
|
||||
guard
|
||||
let callDirection = CallRecord.CallDirection(
|
||||
individualCallInteractionType: individualCallInteraction.callType,
|
||||
@ -147,7 +147,7 @@ public class IndividualCallRecordManagerImpl: IndividualCallRecordManager {
|
||||
tx: tx,
|
||||
)
|
||||
case .matchNotFound:
|
||||
_ = try createRecordForInteraction(
|
||||
_ = createRecordForInteraction(
|
||||
individualCallInteraction: individualCallInteraction,
|
||||
individualCallInteractionRowId: individualCallInteractionRowId,
|
||||
contactThread: contactThread,
|
||||
@ -175,7 +175,7 @@ public class IndividualCallRecordManagerImpl: IndividualCallRecordManager {
|
||||
callEventTimestamp: UInt64,
|
||||
shouldSendSyncMessage: Bool,
|
||||
tx: DBWriteTransaction,
|
||||
) throws -> CallRecord {
|
||||
) -> CallRecord {
|
||||
let callRecord = CallRecord(
|
||||
callId: callId,
|
||||
interactionRowId: individualCallInteractionRowId,
|
||||
@ -186,7 +186,7 @@ public class IndividualCallRecordManagerImpl: IndividualCallRecordManager {
|
||||
callBeganTimestamp: callEventTimestamp,
|
||||
)
|
||||
|
||||
let insertResult = Result(catching: { try callRecordStore.insert(callRecord: callRecord, tx: tx) })
|
||||
callRecordStore.insert(callRecord: callRecord, tx: tx)
|
||||
|
||||
if shouldSendSyncMessage {
|
||||
outgoingSyncMessageManager.sendSyncMessage(
|
||||
@ -197,8 +197,6 @@ public class IndividualCallRecordManagerImpl: IndividualCallRecordManager {
|
||||
)
|
||||
}
|
||||
|
||||
try insertResult.get()
|
||||
|
||||
return callRecord
|
||||
}
|
||||
|
||||
|
||||
@ -19,7 +19,7 @@ import GRDB
|
||||
/// "multiple records with the same expiration time" is equivalent to "multiple
|
||||
/// records with the same `deletedAtTimestamp`.
|
||||
public final class DeletedCallRecordExpirationJob: ExpirationJob<DeletedCallRecord> {
|
||||
private let callLinkStore: any CallLinkRecordStore
|
||||
private let callLinkStore: CallLinkRecordStore
|
||||
private let deletedCallRecordStore: DeletedCallRecordStore
|
||||
|
||||
init(
|
||||
@ -57,15 +57,11 @@ public final class DeletedCallRecordExpirationJob: ExpirationJob<DeletedCallReco
|
||||
tx: tx,
|
||||
)
|
||||
|
||||
do {
|
||||
try deleteCallLinkIfNeeded(conversationId: deletedCallRecord.conversationId, tx: tx)
|
||||
} catch {
|
||||
owsFailDebug("\(error)")
|
||||
}
|
||||
deleteCallLinkIfNeeded(conversationId: deletedCallRecord.conversationId, tx: tx)
|
||||
}
|
||||
|
||||
/// Removes the ``CallLinkRecord`` if there are no more references.
|
||||
private func deleteCallLinkIfNeeded(conversationId: CallRecord.ConversationID, tx: DBWriteTransaction) throws {
|
||||
private func deleteCallLinkIfNeeded(conversationId: CallRecord.ConversationID, tx: DBWriteTransaction) {
|
||||
let callLinkRowId: Int64
|
||||
switch conversationId {
|
||||
case .thread:
|
||||
@ -73,17 +69,12 @@ public final class DeletedCallRecordExpirationJob: ExpirationJob<DeletedCallReco
|
||||
case .callLink(let callLinkRowId2):
|
||||
callLinkRowId = callLinkRowId2
|
||||
}
|
||||
let callLinkRecord = try callLinkStore.fetch(rowId: callLinkRowId, tx: tx) ?? {
|
||||
throw OWSAssertionError("Must be able to find call link.")
|
||||
}()
|
||||
let callLinkRecord = callLinkStore.fetch(rowId: callLinkRowId, tx: tx)
|
||||
.owsFailUnwrap("FOREIGN KEYs mean this must exist.")
|
||||
if callLinkRecord.isDeleted {
|
||||
// We can't delete this until Storage Service is done with it.
|
||||
return
|
||||
}
|
||||
do {
|
||||
try callLinkStore.delete(callLinkRecord, tx: tx)
|
||||
} catch DatabaseError.SQLITE_CONSTRAINT {
|
||||
// We'll delete it later -- something else is still using it.
|
||||
}
|
||||
callLinkStore.deleteIfPossible(callLinkRecord, tx: tx)
|
||||
}
|
||||
}
|
||||
|
||||
@ -310,17 +310,13 @@ public class GroupCallManager {
|
||||
)
|
||||
|
||||
logger.info("Creating record for group call discovered via peek.")
|
||||
do {
|
||||
_ = try groupCallRecordManager.createGroupCallRecordForPeek(
|
||||
callId: callId.rawValue,
|
||||
groupCallInteraction: newGroupCallInteraction,
|
||||
groupCallInteractionRowId: interactionRowId,
|
||||
groupThreadRowId: groupThreadRowId,
|
||||
tx: tx,
|
||||
)
|
||||
} catch let error {
|
||||
owsFailBeta("Failed to insert call record: \(error)")
|
||||
}
|
||||
_ = groupCallRecordManager.createGroupCallRecordForPeek(
|
||||
callId: callId.rawValue,
|
||||
groupCallInteraction: newGroupCallInteraction,
|
||||
groupCallInteractionRowId: interactionRowId,
|
||||
groupThreadRowId: groupThreadRowId,
|
||||
tx: tx,
|
||||
)
|
||||
|
||||
return newGroupCallInteraction
|
||||
}
|
||||
|
||||
@ -235,17 +235,13 @@ public class CallEventInserter {
|
||||
return
|
||||
}
|
||||
|
||||
do {
|
||||
try individualCallRecordManager.createOrUpdateRecordForInteraction(
|
||||
individualCallInteraction: callInteraction,
|
||||
individualCallInteractionRowId: callInteractionRowId,
|
||||
contactThread: thread,
|
||||
contactThreadRowId: threadRowId,
|
||||
callId: callId,
|
||||
tx: tx,
|
||||
)
|
||||
} catch let error {
|
||||
owsFailBeta("Failed to insert call record: \(error)")
|
||||
}
|
||||
individualCallRecordManager.createOrUpdateRecordForInteraction(
|
||||
individualCallInteraction: callInteraction,
|
||||
individualCallInteractionRowId: callInteractionRowId,
|
||||
contactThread: thread,
|
||||
contactThreadRowId: threadRowId,
|
||||
callId: callId,
|
||||
tx: tx,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -794,7 +794,7 @@ extension AppSetup.GlobalsContinuation {
|
||||
dateProvider: { Date() },
|
||||
)
|
||||
|
||||
let callLinkStore = CallLinkRecordStoreImpl()
|
||||
let callLinkStore = CallLinkRecordStore()
|
||||
let deletedCallRecordStore = DeletedCallRecordStoreImpl()
|
||||
let deletedCallRecordExpirationJob = DeletedCallRecordExpirationJob(
|
||||
callLinkStore: callLinkStore,
|
||||
|
||||
@ -87,7 +87,7 @@ public class DependenciesBridge {
|
||||
public let backupTestFlightEntitlementManager: BackupTestFlightEntitlementManager
|
||||
public let badgeCountFetcher: BadgeCountFetcher
|
||||
let blockedRecipientStore: BlockedRecipientStore
|
||||
public let callLinkStore: any CallLinkRecordStore
|
||||
public let callLinkStore: CallLinkRecordStore
|
||||
public let callRecordDeleteManager: any CallRecordDeleteManager
|
||||
public let callRecordMissedCallManager: CallRecordMissedCallManager
|
||||
public let callRecordQuerier: CallRecordQuerier
|
||||
@ -231,7 +231,7 @@ public class DependenciesBridge {
|
||||
backupTestFlightEntitlementManager: BackupTestFlightEntitlementManager,
|
||||
badgeCountFetcher: BadgeCountFetcher,
|
||||
blockedRecipientStore: BlockedRecipientStore,
|
||||
callLinkStore: any CallLinkRecordStore,
|
||||
callLinkStore: CallLinkRecordStore,
|
||||
callRecordDeleteManager: CallRecordDeleteManager,
|
||||
callRecordMissedCallManager: CallRecordMissedCallManager,
|
||||
callRecordQuerier: CallRecordQuerier,
|
||||
|
||||
@ -29,7 +29,7 @@ public class CallRecordDeleteAllJobQueue {
|
||||
private let callRecordConversationIdAdapter: CallRecordSyncMessageConversationIdAdapter
|
||||
|
||||
public init(
|
||||
callLinkStore: any CallLinkRecordStore,
|
||||
callLinkStore: CallLinkRecordStore,
|
||||
callRecordConversationIdAdapter: CallRecordSyncMessageConversationIdAdapter,
|
||||
callRecordDeleteManager: any CallRecordDeleteManager,
|
||||
callRecordQuerier: CallRecordQuerier,
|
||||
@ -119,7 +119,7 @@ private class CallRecordDeleteAllJobRunner: JobRunner {
|
||||
|
||||
private var logger: CallRecordLogger { .shared }
|
||||
|
||||
private let callLinkStore: any CallLinkRecordStore
|
||||
private let callLinkStore: CallLinkRecordStore
|
||||
private let callRecordConversationIdAdapter: CallRecordSyncMessageConversationIdAdapter
|
||||
private let callRecordDeleteManager: any CallRecordDeleteManager
|
||||
private let callRecordQuerier: CallRecordQuerier
|
||||
@ -128,7 +128,7 @@ private class CallRecordDeleteAllJobRunner: JobRunner {
|
||||
private let messageSenderJobQueue: MessageSenderJobQueue
|
||||
|
||||
init(
|
||||
callLinkStore: any CallLinkRecordStore,
|
||||
callLinkStore: CallLinkRecordStore,
|
||||
callRecordConversationIdAdapter: CallRecordSyncMessageConversationIdAdapter,
|
||||
callRecordDeleteManager: any CallRecordDeleteManager,
|
||||
callRecordQuerier: CallRecordQuerier,
|
||||
@ -154,7 +154,7 @@ private class CallRecordDeleteAllJobRunner: JobRunner {
|
||||
jobRecord: jobRecord,
|
||||
retryLimit: Constants.maxRetries,
|
||||
db: db,
|
||||
block: { try await _runJobAttempt(jobRecord) },
|
||||
block: { await _runJobAttempt(jobRecord) },
|
||||
)
|
||||
}
|
||||
|
||||
@ -172,7 +172,7 @@ private class CallRecordDeleteAllJobRunner: JobRunner {
|
||||
|
||||
private func _runJobAttempt(
|
||||
_ jobRecord: CallRecordDeleteAllJobRecord,
|
||||
) async throws {
|
||||
) async {
|
||||
var deleteBeforeTimestamp: UInt64 = {
|
||||
/// We'll prefer the timestamp on the call record if we have it.
|
||||
/// They should be identical in the 99.999% case, but there's a
|
||||
@ -184,16 +184,11 @@ private class CallRecordDeleteAllJobRunner: JobRunner {
|
||||
let callId = jobRecord.deleteAllBeforeCallId,
|
||||
let conversationId = jobRecord.deleteAllBeforeConversationId,
|
||||
let referencedCallRecord: CallRecord = db.read(block: { tx -> CallRecord? in
|
||||
do {
|
||||
return try callRecordConversationIdAdapter.hydrate(
|
||||
conversationId: conversationId,
|
||||
callId: callId,
|
||||
tx: tx,
|
||||
)
|
||||
} catch {
|
||||
owsFailDebug("\(error)")
|
||||
return nil
|
||||
}
|
||||
return callRecordConversationIdAdapter.hydrate(
|
||||
conversationId: conversationId,
|
||||
callId: callId,
|
||||
tx: tx,
|
||||
)
|
||||
})
|
||||
else {
|
||||
return jobRecord.deleteAllBeforeTimestamp
|
||||
@ -272,9 +267,8 @@ private class CallRecordDeleteAllJobRunner: JobRunner {
|
||||
|
||||
switch callRecord.conversationId {
|
||||
case .callLink(let callLinkRowId):
|
||||
let callLinkRecord = try callLinkStore.fetch(rowId: callLinkRowId, tx: tx) ?? {
|
||||
throw OWSAssertionError("Can't fetch CallLink that must exist.")
|
||||
}()
|
||||
let callLinkRecord = callLinkStore.fetch(rowId: callLinkRowId, tx: tx)
|
||||
.owsFailUnwrap("FOREIGN KEYs mean this must exist.")
|
||||
if callLinkRecord.adminPasskey != nil {
|
||||
// These are deleted via Storage Service syncs.
|
||||
} else {
|
||||
@ -345,7 +339,7 @@ private class CallRecordDeleteAllJobRunner: JobRunner {
|
||||
private class CallRecordDeleteAllJobRunnerFactory: JobRunnerFactory {
|
||||
typealias JobRunnerType = CallRecordDeleteAllJobRunner
|
||||
|
||||
private let callLinkStore: any CallLinkRecordStore
|
||||
private let callLinkStore: CallLinkRecordStore
|
||||
private let callRecordConversationIdAdapter: CallRecordSyncMessageConversationIdAdapter
|
||||
private let callRecordDeleteManager: any CallRecordDeleteManager
|
||||
private let callRecordQuerier: CallRecordQuerier
|
||||
@ -354,7 +348,7 @@ private class CallRecordDeleteAllJobRunnerFactory: JobRunnerFactory {
|
||||
private let messageSenderJobQueue: MessageSenderJobQueue
|
||||
|
||||
init(
|
||||
callLinkStore: any CallLinkRecordStore,
|
||||
callLinkStore: CallLinkRecordStore,
|
||||
callRecordConversationIdAdapter: CallRecordSyncMessageConversationIdAdapter,
|
||||
callRecordDeleteManager: any CallRecordDeleteManager,
|
||||
callRecordQuerier: CallRecordQuerier,
|
||||
|
||||
@ -941,10 +941,10 @@ public final class MessageReceiver {
|
||||
let callLinkStore = DependenciesBridge.shared.callLinkStore
|
||||
do {
|
||||
let rootKey = try CallLinkRootKey(callLinkUpdate.rootKey ?? Data())
|
||||
var (callLink, _) = try callLinkStore.fetchOrInsert(rootKey: rootKey, tx: tx)
|
||||
var (callLink, _) = callLinkStore.fetchOrInsert(rootKey: rootKey, tx: tx)
|
||||
callLink.adminPasskey = callLink.adminPasskey ?? callLinkUpdate.adminPasskey
|
||||
callLink.setNeedsFetch()
|
||||
try callLinkStore.update(callLink, tx: tx)
|
||||
callLinkStore.update(callLink, tx: tx)
|
||||
} catch {
|
||||
Logger.warn("Ignoring CallLinkUpdate: \(error)")
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@ class MockCallRecordStore: CallRecordStore {
|
||||
return .matchNotFound
|
||||
}
|
||||
|
||||
func fetchExisting(conversationId: CallRecord.ConversationID, limit: Int?, tx: DBReadTransaction) throws -> [CallRecord] {
|
||||
func fetchExisting(conversationId: CallRecord.ConversationID, limit: Int?, tx: DBReadTransaction) -> [CallRecord] {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
|
||||
@ -682,22 +682,21 @@ public class StorageServiceManagerImpl: NSObject, StorageServiceManager {
|
||||
|
||||
private func cleanUpDeletedCallLinks() async {
|
||||
let callLinkStore = DependenciesBridge.shared.callLinkStore
|
||||
let db = DependenciesBridge.shared.db
|
||||
let deletionThresholdMs = Date.ows_millisecondTimestamp() - RemoteConfig.current.messageQueueTimeMs
|
||||
do {
|
||||
let callLinkRecords = try SSKEnvironment.shared.databaseStorageRef.read { tx in
|
||||
try callLinkStore.fetchWhere(adminDeletedAtTimestampMsIsLessThan: deletionThresholdMs, tx: tx)
|
||||
}
|
||||
if !callLinkRecords.isEmpty {
|
||||
Logger.info("Cleaning up \(callLinkRecords.count) call links that were deleted a while ago.")
|
||||
try await SSKEnvironment.shared.databaseStorageRef.awaitableWrite { tx in
|
||||
for callLinkRecord in callLinkRecords {
|
||||
try callLinkStore.delete(callLinkRecord, tx: tx)
|
||||
}
|
||||
|
||||
let callLinkRecords = db.read { tx in
|
||||
callLinkStore.fetchWhere(adminDeletedAtTimestampMsIsLessThan: deletionThresholdMs, tx: tx)
|
||||
}
|
||||
|
||||
if !callLinkRecords.isEmpty {
|
||||
Logger.info("Cleaning up \(callLinkRecords.count) call links that were deleted a while ago.")
|
||||
await db.awaitableWrite { tx in
|
||||
for callLinkRecord in callLinkRecords {
|
||||
callLinkStore.deleteIfPossible(callLinkRecord, tx: tx)
|
||||
}
|
||||
recordPendingUpdates(callLinkRootKeys: callLinkRecords.map(\.rootKey))
|
||||
}
|
||||
} catch {
|
||||
owsFailDebug("Couldn't clean up deleted call links: \(error)")
|
||||
recordPendingUpdates(callLinkRootKeys: callLinkRecords.map(\.rootKey))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1370,12 +1369,8 @@ class StorageServiceOperation {
|
||||
|
||||
let callLinkUpdater = buildCallLinkUpdater()
|
||||
let callLinkStore = callLinkUpdater.recordUpdater.callLinkStore
|
||||
do {
|
||||
try callLinkStore.fetchAll(tx: transaction).forEach {
|
||||
createRecord(localId: $0.rootKey.bytes, stateUpdater: callLinkUpdater)
|
||||
}
|
||||
} catch {
|
||||
owsFailDebug("Couldn't add CallLinks to manifest: \(error)")
|
||||
callLinkStore.fetchAll(tx: transaction).forEach {
|
||||
createRecord(localId: $0.rootKey.bytes, stateUpdater: callLinkUpdater)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1699,7 +1694,7 @@ class StorageServiceOperation {
|
||||
let callLinkStore = DependenciesBridge.shared.callLinkStore
|
||||
guard
|
||||
let callLinkRootKey = try? CallLinkRootKey(callLinkRootKeyData),
|
||||
let callLinkRecord = try? callLinkStore.fetch(roomId: callLinkRootKey.deriveRoomId(), tx: transaction),
|
||||
let callLinkRecord = callLinkStore.fetch(roomId: callLinkRootKey.deriveRoomId(), tx: transaction),
|
||||
callLinkRecord.adminPasskey != nil
|
||||
else {
|
||||
continue
|
||||
|
||||
@ -2163,12 +2163,12 @@ class StorageServiceCallLinkRecordUpdater: StorageServiceRecordUpdater {
|
||||
typealias IdType = Data
|
||||
typealias RecordType = StorageServiceProtoCallLinkRecord
|
||||
|
||||
let callLinkStore: any CallLinkRecordStore
|
||||
let callLinkStore: CallLinkRecordStore
|
||||
private let callRecordDeleteManager: any CallRecordDeleteManager
|
||||
private let callRecordStore: any CallRecordStore
|
||||
|
||||
init(
|
||||
callLinkStore: any CallLinkRecordStore,
|
||||
callLinkStore: CallLinkRecordStore,
|
||||
callRecordDeleteManager: any CallRecordDeleteManager,
|
||||
callRecordStore: any CallRecordStore,
|
||||
) {
|
||||
@ -2193,13 +2193,7 @@ class StorageServiceCallLinkRecordUpdater: StorageServiceRecordUpdater {
|
||||
return nil
|
||||
}
|
||||
let roomId = rootKey.deriveRoomId()
|
||||
let callLink: CallLinkRecord?
|
||||
do {
|
||||
callLink = try self.callLinkStore.fetch(roomId: roomId, tx: tx)
|
||||
} catch {
|
||||
owsFailDebug("Skipping CallLink that can't be fetched: \(rootKey.description)")
|
||||
return nil
|
||||
}
|
||||
let callLink = self.callLinkStore.fetch(roomId: roomId, tx: tx)
|
||||
|
||||
guard let callLink, callLink.adminPasskey != nil || callLink.adminDeletedAtTimestampMs != nil else {
|
||||
// We're not an admin, so this link doesn't go in Storage Service.
|
||||
@ -2228,24 +2222,20 @@ class StorageServiceCallLinkRecordUpdater: StorageServiceRecordUpdater {
|
||||
owsFailDebug("invalid rootKey")
|
||||
return .invalid
|
||||
}
|
||||
do {
|
||||
var (callLink, _) = try self.callLinkStore.fetchOrInsert(rootKey: rootKey, tx: tx)
|
||||
// The earliest deletion timestamp takes precendence when merging.
|
||||
if record.deletedAtTimestampMs > 0 || callLink.adminDeletedAtTimestampMs != nil {
|
||||
self.callRecordDeleteManager.deleteCallRecords(
|
||||
try self.callRecordStore.fetchExisting(conversationId: .callLink(callLinkRowId: callLink.id), limit: nil, tx: tx),
|
||||
sendSyncMessageOnDelete: false,
|
||||
tx: tx,
|
||||
)
|
||||
callLink.markDeleted(atTimestampMs: [record.deletedAtTimestampMs, callLink.adminDeletedAtTimestampMs].compacted().min()!)
|
||||
} else if let adminPasskey = record.adminPasskey?.nilIfEmpty {
|
||||
callLink.adminPasskey = adminPasskey
|
||||
callLink.setNeedsFetch()
|
||||
}
|
||||
try self.callLinkStore.update(callLink, tx: tx)
|
||||
} catch {
|
||||
owsFailDebug("Couldn't merge CallLink \(rootKey.description): \(error)")
|
||||
var (callLink, _) = self.callLinkStore.fetchOrInsert(rootKey: rootKey, tx: tx)
|
||||
// The earliest deletion timestamp takes precendence when merging.
|
||||
if record.deletedAtTimestampMs > 0 || callLink.adminDeletedAtTimestampMs != nil {
|
||||
self.callRecordDeleteManager.deleteCallRecords(
|
||||
self.callRecordStore.fetchExisting(conversationId: .callLink(callLinkRowId: callLink.id), limit: nil, tx: tx),
|
||||
sendSyncMessageOnDelete: false,
|
||||
tx: tx,
|
||||
)
|
||||
callLink.markDeleted(atTimestampMs: [record.deletedAtTimestampMs, callLink.adminDeletedAtTimestampMs].compacted().min()!)
|
||||
} else if let adminPasskey = record.adminPasskey?.nilIfEmpty {
|
||||
callLink.adminPasskey = adminPasskey
|
||||
callLink.setNeedsFetch()
|
||||
}
|
||||
self.callLinkStore.update(callLink, tx: tx)
|
||||
return .merged(needsUpdate: false, rootKey.bytes)
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,7 +31,7 @@ final class CallRecordDeleteManagerTest: XCTestCase {
|
||||
|
||||
// We never call .start() on this job, so this is a no-op instance.
|
||||
mockDeletedCallRecordExpirationJob = DeletedCallRecordExpirationJob(
|
||||
callLinkStore: MockCallLinkRecordStore(),
|
||||
callLinkStore: CallLinkRecordStore(),
|
||||
dateProvider: { Date() },
|
||||
db: mockDB,
|
||||
deletedCallRecordStore: mockDeletedCallRecordStore,
|
||||
|
||||
@ -247,11 +247,11 @@ private extension CallRecord {
|
||||
}
|
||||
|
||||
private class MockConversationIdAdapter: CallRecordSyncMessageConversationIdAdapter {
|
||||
func hydrate(conversationId: Data, callId: UInt64, tx: DBReadTransaction) throws -> CallRecord? {
|
||||
func hydrate(conversationId: Data, callId: UInt64, tx: DBReadTransaction) -> CallRecord? {
|
||||
owsFail("Not implemented!")
|
||||
}
|
||||
|
||||
func getConversationId(callRecord: CallRecord, tx: DBReadTransaction) throws -> Data {
|
||||
func getConversationId(callRecord: CallRecord, tx: DBReadTransaction) -> Data {
|
||||
return Aci.randomForTesting().serviceIdBinary
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,11 +90,11 @@ final class CallRecordStoreTest: XCTestCase {
|
||||
|
||||
// MARK: - Insert and fetch
|
||||
|
||||
func testInsertAndFetch() throws {
|
||||
func testInsertAndFetch() {
|
||||
let callRecord = makeCallRecord()
|
||||
|
||||
try inMemoryDB.write { tx in
|
||||
try callRecordStore._insert(callRecord: callRecord, tx: tx)
|
||||
inMemoryDB.write { tx in
|
||||
callRecordStore.insert(callRecord: callRecord, tx: tx)
|
||||
}
|
||||
|
||||
let fetchedByCallId = inMemoryDB.read { tx in
|
||||
@ -139,17 +139,17 @@ final class CallRecordStoreTest: XCTestCase {
|
||||
|
||||
// MARK: - Delete
|
||||
|
||||
func testDelete() throws {
|
||||
func testDelete() {
|
||||
let callRecord1 = makeCallRecord()
|
||||
let callRecord2 = makeCallRecord()
|
||||
|
||||
try inMemoryDB.write { tx in
|
||||
try callRecordStore._insert(callRecord: callRecord1, tx: tx)
|
||||
try callRecordStore._insert(callRecord: callRecord2, tx: tx)
|
||||
inMemoryDB.write { tx in
|
||||
callRecordStore.insert(callRecord: callRecord1, tx: tx)
|
||||
callRecordStore.insert(callRecord: callRecord2, tx: tx)
|
||||
}
|
||||
|
||||
inMemoryDB.write { tx in
|
||||
callRecordStore._delete(callRecords: [callRecord1, callRecord2], tx: tx)
|
||||
callRecordStore.delete(callRecords: [callRecord1, callRecord2], tx: tx)
|
||||
}
|
||||
|
||||
inMemoryDB.read { tx in
|
||||
@ -176,15 +176,15 @@ final class CallRecordStoreTest: XCTestCase {
|
||||
|
||||
// MARK: - updateCallStatus
|
||||
|
||||
func testUpdateRecordStatus() throws {
|
||||
func testUpdateRecordStatus() {
|
||||
let callRecord = makeCallRecord(callStatus: .group(.generic))
|
||||
|
||||
try inMemoryDB.write { tx in
|
||||
try callRecordStore._insert(callRecord: callRecord, tx: tx)
|
||||
inMemoryDB.write { tx in
|
||||
callRecordStore.insert(callRecord: callRecord, tx: tx)
|
||||
}
|
||||
|
||||
inMemoryDB.write { tx in
|
||||
callRecordStore._updateCallAndUnreadStatus(
|
||||
callRecordStore.updateCallAndUnreadStatus(
|
||||
callRecord: callRecord,
|
||||
newCallStatus: .group(.joined),
|
||||
tx: tx,
|
||||
@ -203,7 +203,7 @@ final class CallRecordStoreTest: XCTestCase {
|
||||
XCTAssertTrue(callRecord.matches(fetched))
|
||||
}
|
||||
|
||||
func testUpdateRecordStatusAndUnread() throws {
|
||||
func testUpdateRecordStatusAndUnread() {
|
||||
/// Some of these are not updates that can happen in production; for
|
||||
/// example, a missed individual call cannot move into a pending state.
|
||||
///
|
||||
@ -240,10 +240,10 @@ final class CallRecordStoreTest: XCTestCase {
|
||||
let callRecord = makeCallRecord(callStatus: beforeCallStatus)
|
||||
XCTAssertEqual(callRecord.unreadStatus, beforeUnreadStatus)
|
||||
|
||||
try inMemoryDB.write { tx in
|
||||
try callRecordStore._insert(callRecord: callRecord, tx: tx)
|
||||
inMemoryDB.write { tx in
|
||||
callRecordStore.insert(callRecord: callRecord, tx: tx)
|
||||
|
||||
callRecordStore._updateCallAndUnreadStatus(
|
||||
callRecordStore.updateCallAndUnreadStatus(
|
||||
callRecord: callRecord,
|
||||
newCallStatus: afterCallStatus,
|
||||
tx: tx,
|
||||
@ -263,13 +263,13 @@ final class CallRecordStoreTest: XCTestCase {
|
||||
|
||||
// MARK: - markAsRead
|
||||
|
||||
func testMarkAsRead() throws {
|
||||
func testMarkAsRead() {
|
||||
let unreadCallRecord = makeCallRecord(callStatus: .group(.ringingMissed))
|
||||
XCTAssertEqual(unreadCallRecord.unreadStatus, .unread)
|
||||
|
||||
try inMemoryDB.write { tx in
|
||||
try callRecordStore._insert(callRecord: unreadCallRecord, tx: tx)
|
||||
try callRecordStore.markAsRead(callRecord: unreadCallRecord, tx: tx)
|
||||
inMemoryDB.write { tx in
|
||||
callRecordStore.insert(callRecord: unreadCallRecord, tx: tx)
|
||||
callRecordStore.markAsRead(callRecord: unreadCallRecord, tx: tx)
|
||||
XCTAssertEqual(unreadCallRecord.unreadStatus, .read)
|
||||
}
|
||||
|
||||
@ -286,12 +286,12 @@ final class CallRecordStoreTest: XCTestCase {
|
||||
|
||||
// MARK: - updateWithMergedThread
|
||||
|
||||
func testUpdateWithMergedThread() throws {
|
||||
func testUpdateWithMergedThread() {
|
||||
let callRecord = makeCallRecord()
|
||||
let (newThreadRowId, _) = insertThreadAndInteraction()
|
||||
|
||||
try inMemoryDB.write { tx in
|
||||
try callRecordStore._insert(callRecord: callRecord, tx: tx)
|
||||
inMemoryDB.write { tx in
|
||||
callRecordStore.insert(callRecord: callRecord, tx: tx)
|
||||
}
|
||||
|
||||
inMemoryDB.write { tx in
|
||||
@ -321,8 +321,8 @@ final class CallRecordStoreTest: XCTestCase {
|
||||
func testDeletingInteractionDeletesCallRecord() throws {
|
||||
let callRecord = makeCallRecord()
|
||||
|
||||
try inMemoryDB.write { tx in
|
||||
try callRecordStore._insert(callRecord: callRecord, tx: tx)
|
||||
inMemoryDB.write { tx in
|
||||
callRecordStore.insert(callRecord: callRecord, tx: tx)
|
||||
}
|
||||
|
||||
try inMemoryDB.write { tx in
|
||||
@ -350,8 +350,8 @@ final class CallRecordStoreTest: XCTestCase {
|
||||
func testDeletingThreadFailsIfCallRecordExtant() throws {
|
||||
let callRecord = makeCallRecord()
|
||||
|
||||
try inMemoryDB.write { tx in
|
||||
try callRecordStore._insert(callRecord: callRecord, tx: tx)
|
||||
inMemoryDB.write { tx in
|
||||
callRecordStore.insert(callRecord: callRecord, tx: tx)
|
||||
}
|
||||
|
||||
try inMemoryDB.write { tx in
|
||||
|
||||
@ -56,11 +56,11 @@ final class GroupCallRecordManagerTest: XCTestCase {
|
||||
|
||||
// MARK: - Create or update record
|
||||
|
||||
func testCreateOrUpdate_CallsCreateAndInsertsInteraction() throws {
|
||||
func testCreateOrUpdate_CallsCreateAndInsertsInteraction() {
|
||||
let (thread, _) = createInteraction()
|
||||
|
||||
try mockDB.write { tx in
|
||||
try snoopingGroupCallRecordManager.createOrUpdateCallRecord(
|
||||
mockDB.write { tx in
|
||||
snoopingGroupCallRecordManager.createOrUpdateCallRecord(
|
||||
callId: .maxRandom,
|
||||
groupThread: thread,
|
||||
groupThreadRowId: thread.sqliteRowId!,
|
||||
@ -76,7 +76,7 @@ final class GroupCallRecordManagerTest: XCTestCase {
|
||||
XCTAssertTrue(snoopingGroupCallRecordManager.didAskToCreate)
|
||||
}
|
||||
|
||||
func testCreateOrUpdate_CallsUpdate() throws {
|
||||
func testCreateOrUpdate_CallsUpdate() {
|
||||
let (thread, interaction) = createInteraction()
|
||||
|
||||
let callRecord = CallRecord(
|
||||
@ -90,8 +90,8 @@ final class GroupCallRecordManagerTest: XCTestCase {
|
||||
)
|
||||
mockCallRecordStore.callRecords.append(callRecord)
|
||||
|
||||
try mockDB.write { tx in
|
||||
try snoopingGroupCallRecordManager.createOrUpdateCallRecord(
|
||||
mockDB.write { tx in
|
||||
snoopingGroupCallRecordManager.createOrUpdateCallRecord(
|
||||
callId: callRecord.callId,
|
||||
groupThread: thread,
|
||||
groupThreadRowId: thread.sqliteRowId!,
|
||||
@ -106,13 +106,13 @@ final class GroupCallRecordManagerTest: XCTestCase {
|
||||
XCTAssertTrue(snoopingGroupCallRecordManager.didAskToUpdate)
|
||||
}
|
||||
|
||||
func testCreateOrUpdate_DoesNothingIfRecentlyDeleted() throws {
|
||||
func testCreateOrUpdate_DoesNothingIfRecentlyDeleted() {
|
||||
let (thread, _) = createInteraction()
|
||||
|
||||
mockCallRecordStore.fetchMock = { .matchDeleted }
|
||||
|
||||
try mockDB.write { tx in
|
||||
try snoopingGroupCallRecordManager.createOrUpdateCallRecord(
|
||||
mockDB.write { tx in
|
||||
snoopingGroupCallRecordManager.createOrUpdateCallRecord(
|
||||
callId: .maxRandom,
|
||||
groupThread: thread,
|
||||
groupThreadRowId: thread.sqliteRowId!,
|
||||
@ -129,12 +129,12 @@ final class GroupCallRecordManagerTest: XCTestCase {
|
||||
|
||||
// MARK: - Create group call record
|
||||
|
||||
func testCreateGroupCallRecord() throws {
|
||||
func testCreateGroupCallRecord() {
|
||||
let (thread1, interaction1) = createInteraction()
|
||||
let (thread2, interaction2) = createInteraction()
|
||||
|
||||
_ = try mockDB.write { tx in
|
||||
try groupCallRecordManager.createGroupCallRecord(
|
||||
_ = mockDB.write { tx in
|
||||
groupCallRecordManager.createGroupCallRecord(
|
||||
callId: .maxRandom,
|
||||
groupCallInteraction: interaction1,
|
||||
groupCallInteractionRowId: interaction1.sqliteRowId!,
|
||||
@ -151,8 +151,8 @@ final class GroupCallRecordManagerTest: XCTestCase {
|
||||
XCTAssertEqual(mockCallRecordStore.callRecords.count, 1)
|
||||
XCTAssertEqual(mockOutgoingSyncMessageManager.syncMessageSendCount, 0)
|
||||
|
||||
_ = try mockDB.write { tx in
|
||||
try groupCallRecordManager.createGroupCallRecord(
|
||||
_ = mockDB.write { tx in
|
||||
groupCallRecordManager.createGroupCallRecord(
|
||||
callId: .maxRandom,
|
||||
groupCallInteraction: interaction2,
|
||||
groupCallInteractionRowId: interaction2.sqliteRowId!,
|
||||
@ -171,11 +171,11 @@ final class GroupCallRecordManagerTest: XCTestCase {
|
||||
XCTAssertEqual(mockOutgoingSyncMessageManager.syncMessageSendCount, 1)
|
||||
}
|
||||
|
||||
func testCreateGroupCallRecordForPeek() throws {
|
||||
func testCreateGroupCallRecordForPeek() {
|
||||
let (thread, interaction) = createInteraction()
|
||||
|
||||
_ = try mockDB.write { tx in
|
||||
try groupCallRecordManager.createGroupCallRecordForPeek(
|
||||
mockDB.write { tx in
|
||||
_ = groupCallRecordManager.createGroupCallRecordForPeek(
|
||||
callId: .maxRandom,
|
||||
groupCallInteraction: interaction,
|
||||
groupCallInteractionRowId: interaction.sqliteRowId!,
|
||||
@ -197,7 +197,7 @@ final class GroupCallRecordManagerTest: XCTestCase {
|
||||
|
||||
// MARK: Update record
|
||||
|
||||
func testUpdate_Updates() throws {
|
||||
func testUpdate_Updates() {
|
||||
let (thread, interaction) = createInteraction()
|
||||
|
||||
let callRecord = CallRecord(
|
||||
@ -211,8 +211,8 @@ final class GroupCallRecordManagerTest: XCTestCase {
|
||||
)
|
||||
mockCallRecordStore.callRecords.append(callRecord)
|
||||
|
||||
try mockDB.write { tx in
|
||||
try groupCallRecordManager.createOrUpdateCallRecord(
|
||||
mockDB.write { tx in
|
||||
groupCallRecordManager.createOrUpdateCallRecord(
|
||||
callId: callRecord.callId,
|
||||
groupThread: thread,
|
||||
groupThreadRowId: thread.sqliteRowId!,
|
||||
@ -229,7 +229,7 @@ final class GroupCallRecordManagerTest: XCTestCase {
|
||||
XCTAssertEqual(mockOutgoingSyncMessageManager.syncMessageSendCount, 1)
|
||||
}
|
||||
|
||||
func testUpdate_SkipsDirectionAndSyncMessage() throws {
|
||||
func testUpdate_SkipsDirectionAndSyncMessage() {
|
||||
let (thread, interaction) = createInteraction()
|
||||
|
||||
let callRecord = CallRecord(
|
||||
@ -243,8 +243,8 @@ final class GroupCallRecordManagerTest: XCTestCase {
|
||||
)
|
||||
mockCallRecordStore.callRecords.append(callRecord)
|
||||
|
||||
try mockDB.write { tx in
|
||||
try groupCallRecordManager.createOrUpdateCallRecord(
|
||||
mockDB.write { tx in
|
||||
groupCallRecordManager.createOrUpdateCallRecord(
|
||||
callId: callRecord.callId,
|
||||
groupThread: thread,
|
||||
groupThreadRowId: thread.sqliteRowId!,
|
||||
@ -265,7 +265,7 @@ final class GroupCallRecordManagerTest: XCTestCase {
|
||||
/// status that's illegal per the record's current state.
|
||||
///
|
||||
/// In this test, we try to illegally go from "joined" to "generic".
|
||||
func testUpdate_SkipsSyncMessageIfStatusTransitionDisallowed() throws {
|
||||
func testUpdate_SkipsSyncMessageIfStatusTransitionDisallowed() {
|
||||
let (thread, interaction) = createInteraction()
|
||||
|
||||
let callRecord = CallRecord(
|
||||
@ -279,8 +279,8 @@ final class GroupCallRecordManagerTest: XCTestCase {
|
||||
)
|
||||
mockCallRecordStore.callRecords.append(callRecord)
|
||||
|
||||
try mockDB.write { tx in
|
||||
try groupCallRecordManager.createOrUpdateCallRecord(
|
||||
mockDB.write { tx in
|
||||
groupCallRecordManager.createOrUpdateCallRecord(
|
||||
callId: callRecord.callId,
|
||||
groupThread: thread,
|
||||
groupThreadRowId: thread.sqliteRowId!,
|
||||
@ -297,7 +297,7 @@ final class GroupCallRecordManagerTest: XCTestCase {
|
||||
XCTAssertEqual(mockOutgoingSyncMessageManager.syncMessageSendCount, 0)
|
||||
}
|
||||
|
||||
func testUpdate_UpdatesCallBeganTimestamp() throws {
|
||||
func testUpdate_UpdatesCallBeganTimestamp() {
|
||||
let (thread, interaction) = createInteraction()
|
||||
|
||||
let callRecord = CallRecord(
|
||||
@ -311,8 +311,8 @@ final class GroupCallRecordManagerTest: XCTestCase {
|
||||
)
|
||||
mockCallRecordStore.callRecords.append(callRecord)
|
||||
|
||||
try mockDB.write { tx in
|
||||
try groupCallRecordManager.createOrUpdateCallRecord(
|
||||
mockDB.write { tx in
|
||||
groupCallRecordManager.createOrUpdateCallRecord(
|
||||
callId: callRecord.callId,
|
||||
groupThread: thread,
|
||||
groupThreadRowId: thread.sqliteRowId!,
|
||||
|
||||
@ -42,7 +42,7 @@ final class IncomingCallEventSyncMessageManagerTest: XCTestCase {
|
||||
|
||||
incomingSyncMessageManager = IncomingCallEventSyncMessageManagerImpl(
|
||||
adHocCallRecordManager: MockAdHocCallRecordManager(),
|
||||
callLinkStore: MockCallLinkRecordStore(),
|
||||
callLinkStore: CallLinkRecordStore(),
|
||||
callRecordStore: mockCallRecordStore,
|
||||
callRecordDeleteManager: mockCallRecordDeleteManager,
|
||||
groupCallRecordManager: mockGroupCallRecordManager,
|
||||
|
||||
@ -96,11 +96,11 @@ final class IndividualCallRecordManagerTest: XCTestCase {
|
||||
|
||||
// MARK: - createOrUpdateRecordForInteraction
|
||||
|
||||
func testCreateOrUpdate_noRecordExists() throws {
|
||||
func testCreateOrUpdate_noRecordExists() {
|
||||
let (thread, interaction) = createInteraction()
|
||||
|
||||
try mockDB.write { tx in
|
||||
try individualCallRecordManager.createOrUpdateRecordForInteraction(
|
||||
mockDB.write { tx in
|
||||
individualCallRecordManager.createOrUpdateRecordForInteraction(
|
||||
individualCallInteraction: interaction,
|
||||
individualCallInteractionRowId: interaction.sqliteRowId!,
|
||||
contactThread: thread,
|
||||
@ -114,7 +114,7 @@ final class IndividualCallRecordManagerTest: XCTestCase {
|
||||
XCTAssertEqual(mockOutgoingSyncMessageManager.syncMessageSendCount, 1)
|
||||
}
|
||||
|
||||
func testCreateOrUpdate_recordExists() throws {
|
||||
func testCreateOrUpdate_recordExists() {
|
||||
let (thread, interaction) = createInteraction(callType: .incomingDeclined)
|
||||
let callId = UInt64.maxRandom
|
||||
|
||||
@ -129,8 +129,8 @@ final class IndividualCallRecordManagerTest: XCTestCase {
|
||||
)
|
||||
mockCallRecordStore.callRecords.append(callRecord)
|
||||
|
||||
try mockDB.write { tx in
|
||||
try individualCallRecordManager.createOrUpdateRecordForInteraction(
|
||||
mockDB.write { tx in
|
||||
individualCallRecordManager.createOrUpdateRecordForInteraction(
|
||||
individualCallInteraction: interaction,
|
||||
individualCallInteractionRowId: interaction.sqliteRowId!,
|
||||
contactThread: thread,
|
||||
@ -144,14 +144,14 @@ final class IndividualCallRecordManagerTest: XCTestCase {
|
||||
XCTAssertEqual(mockOutgoingSyncMessageManager.syncMessageSendCount, 1)
|
||||
}
|
||||
|
||||
func testCreateOrUpdate_nothingIfRecordRecentlyDeleted() throws {
|
||||
func testCreateOrUpdate_nothingIfRecordRecentlyDeleted() {
|
||||
let (thread, interaction) = createInteraction(callType: .incomingDeclined)
|
||||
let callId = UInt64.maxRandom
|
||||
|
||||
mockCallRecordStore.fetchMock = { .matchDeleted }
|
||||
|
||||
try mockDB.write { tx in
|
||||
try individualCallRecordManager.createOrUpdateRecordForInteraction(
|
||||
mockDB.write { tx in
|
||||
individualCallRecordManager.createOrUpdateRecordForInteraction(
|
||||
individualCallInteraction: interaction,
|
||||
individualCallInteractionRowId: interaction.sqliteRowId!,
|
||||
contactThread: thread,
|
||||
@ -167,11 +167,11 @@ final class IndividualCallRecordManagerTest: XCTestCase {
|
||||
|
||||
// MARK: - createRecordForInteraction
|
||||
|
||||
func testCreate_noSyncMessage() throws {
|
||||
func testCreate_noSyncMessage() {
|
||||
let (thread, interaction) = createInteraction()
|
||||
|
||||
try mockDB.write { tx in
|
||||
_ = try individualCallRecordManager.createRecordForInteraction(
|
||||
mockDB.write { tx in
|
||||
_ = individualCallRecordManager.createRecordForInteraction(
|
||||
individualCallInteraction: interaction,
|
||||
individualCallInteractionRowId: interaction.sqliteRowId!,
|
||||
contactThread: thread,
|
||||
@ -190,11 +190,11 @@ final class IndividualCallRecordManagerTest: XCTestCase {
|
||||
XCTAssertEqual(mockOutgoingSyncMessageManager.syncMessageSendCount, 0)
|
||||
}
|
||||
|
||||
func testCreate_syncMessage() throws {
|
||||
func testCreate_syncMessage() {
|
||||
let (thread, interaction) = createInteraction()
|
||||
|
||||
try mockDB.write { tx in
|
||||
_ = try individualCallRecordManager.createRecordForInteraction(
|
||||
mockDB.write { tx in
|
||||
_ = individualCallRecordManager.createRecordForInteraction(
|
||||
individualCallInteraction: interaction,
|
||||
individualCallInteractionRowId: interaction.sqliteRowId!,
|
||||
contactThread: thread,
|
||||
@ -311,9 +311,9 @@ private class SnoopingIndividualCallRecordManagerImpl: IndividualCallRecordManag
|
||||
var didAskToCreateRecord: CallRecord.CallStatus.IndividualCallStatus?
|
||||
var didAskToUpdateRecord: CallRecord.CallStatus.IndividualCallStatus?
|
||||
|
||||
override func createRecordForInteraction(individualCallInteraction: TSCall, individualCallInteractionRowId: Int64, contactThread: TSContactThread, contactThreadRowId: Int64, callId: UInt64, callType: CallRecord.CallType, callDirection: CallRecord.CallDirection, individualCallStatus: CallRecord.CallStatus.IndividualCallStatus, callEventTimestamp: UInt64, shouldSendSyncMessage: Bool, tx: DBWriteTransaction) throws -> CallRecord {
|
||||
override func createRecordForInteraction(individualCallInteraction: TSCall, individualCallInteractionRowId: Int64, contactThread: TSContactThread, contactThreadRowId: Int64, callId: UInt64, callType: CallRecord.CallType, callDirection: CallRecord.CallDirection, individualCallStatus: CallRecord.CallStatus.IndividualCallStatus, callEventTimestamp: UInt64, shouldSendSyncMessage: Bool, tx: DBWriteTransaction) -> CallRecord {
|
||||
didAskToCreateRecord = individualCallStatus
|
||||
return try super.createRecordForInteraction(individualCallInteraction: individualCallInteraction, individualCallInteractionRowId: individualCallInteractionRowId, contactThread: contactThread, contactThreadRowId: contactThreadRowId, callId: callId, callType: callType, callDirection: callDirection, individualCallStatus: individualCallStatus, callEventTimestamp: callEventTimestamp, shouldSendSyncMessage: shouldSendSyncMessage, tx: tx)
|
||||
return super.createRecordForInteraction(individualCallInteraction: individualCallInteraction, individualCallInteractionRowId: individualCallInteractionRowId, contactThread: contactThread, contactThreadRowId: contactThreadRowId, callId: callId, callType: callType, callDirection: callDirection, individualCallStatus: individualCallStatus, callEventTimestamp: callEventTimestamp, shouldSendSyncMessage: shouldSendSyncMessage, tx: tx)
|
||||
}
|
||||
|
||||
override func updateRecord(contactThread: TSContactThread, existingCallRecord: CallRecord, newIndividualCallStatus: CallRecord.CallStatus.IndividualCallStatus, shouldSendSyncMessage: Bool, tx: DBWriteTransaction) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user