Post a Calls Tab notification when marking unended group calls as ended

This commit is contained in:
Sasha Weiss 2024-04-18 15:33:08 -07:00 committed by GitHub
parent 8d9d04af42
commit df99ce0055
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 111 additions and 44 deletions

View File

@ -175,10 +175,6 @@ class WebRTCCallMessageHandler: CallMessageHandler {
for groupThread: TSGroupThread,
serverReceivedTimestamp: UInt64
) async {
GroupCallPeekLogger.shared.info(
"Received group call update message for thread \(groupThread.uniqueId), eraId \(String(describing: updateMessage.eraID))"
)
await groupCallManager.peekGroupCallAndUpdateThread(
groupThread,
peekTrigger: .receivedGroupUpdateMessage(

View File

@ -338,7 +338,7 @@ class DebugUICallsTab: DebugUIPage {
thread: groupThread,
sentAtTimestamp: nowTimestamp
)
callInteraction.update(withHasEnded: true, transaction: tx)
callInteraction.hasEnded = true
callInteraction.anyInsert(transaction: tx)
let callRecord = CallRecord(

View File

@ -194,10 +194,6 @@ class NSECallMessageHandler: CallMessageHandler {
for groupThread: TSGroupThread,
serverReceivedTimestamp: UInt64
) async {
GroupCallPeekLogger.shared.info(
"Received group call update message for thread \(groupThread.uniqueId), eraId \(String(describing: updateMessage.eraID))"
)
await groupCallManager.peekGroupCallAndUpdateThread(
groupThread,
peekTrigger: .receivedGroupUpdateMessage(

View File

@ -87,6 +87,40 @@ public extension InteractionStore {
groupCallInteraction.joinedMemberUuids = joinedMemberAcis.map { $0.serviceIdUppercaseString }
}
postUpdatedNotification(
callId: callId,
groupThreadRowId: groupThreadRowId,
notificationScheduler: notificationScheduler,
tx: tx
)
}
func markGroupCallInteractionAsEnded(
groupCallInteraction: OWSGroupCallMessage,
callId: UInt64,
groupThreadRowId: Int64,
notificationScheduler: Scheduler,
tx: DBWriteTransaction
) {
updateInteraction(groupCallInteraction, tx: tx) { groupCallInteraction in
groupCallInteraction.hasEnded = true
groupCallInteraction.joinedMemberUuids = []
}
postUpdatedNotification(
callId: callId,
groupThreadRowId: groupThreadRowId,
notificationScheduler: notificationScheduler,
tx: tx
)
}
private func postUpdatedNotification(
callId: UInt64,
groupThreadRowId: Int64,
notificationScheduler: Scheduler,
tx: DBWriteTransaction
) {
tx.addAsyncCompletion(on: notificationScheduler) {
NotificationCenter.default.post(GroupCallInteractionUpdatedNotification(
callId: callId,

View File

@ -93,8 +93,6 @@ NS_DESIGNATED_INITIALIZER NS_SWIFT_NAME(init(grdbId:uniqueId:receivedAtTimestamp
- (NSString *)systemTextWithTransaction:(SDSAnyReadTransaction *)transaction;
- (void)updateWithHasEnded:(BOOL)hasEnded transaction:(SDSAnyWriteTransaction *)transaction;
@end
NS_ASSUME_NONNULL_END

View File

@ -198,15 +198,6 @@ NS_ASSUME_NONNULL_BEGIN
}
}
- (void)updateWithHasEnded:(BOOL)hasEnded transaction:(SDSAnyWriteTransaction *)transaction
{
[self anyUpdateGroupCallMessageWithTransaction:transaction
block:^(OWSGroupCallMessage *message) {
message.hasEnded = hasEnded;
message.joinedMemberUuids = @[];
}];
}
#pragma mark - Private
- (NSString *)participantNameForAddress:(SignalServiceAddress *)address transaction:(SDSAnyReadTransaction *)transaction

View File

@ -18,7 +18,7 @@ public class CurrentCallNoOpThreadProvider: CurrentCallThreadProvider {
/// Fetches & updates group call state.
public class GroupCallManager {
/// The triggers that may kick off a group call peek.
public enum PeekTrigger {
public enum PeekTrigger: CustomStringConvertible {
/// We received a group update message, and are peeking in response.
case receivedGroupUpdateMessage(eraId: String?, messageTimestamp: UInt64)
@ -33,6 +33,16 @@ public class GroupCallManager {
return timestamp
}
}
public var description: String {
switch self {
case .receivedGroupUpdateMessage(let eraId, _):
let callId = eraId.map { CallId(eraId: $0) }
return "GroupCallUpdateMessage, callId: \(callId?.description ?? "(null)")"
case .localEvent(let timestamp):
return "LocalEvent"
}
}
}
private var callRecordStore: CallRecordStore { DependenciesBridge.shared.callRecordStore }
@ -60,14 +70,18 @@ public class GroupCallManager {
_ thread: TSGroupThread,
peekTrigger: PeekTrigger
) async {
// If the currentCall is for the provided thread, we don't need to perform an explicit
// peek. Connected calls will receive automatic updates from RingRTC
logger.info("Peek requested for thread \(thread.uniqueId) with trigger: \(peekTrigger)")
// If the currentCall is for the provided thread, we don't need to
// perform an explicit peek. Connected calls will receive automatic
// updates from RingRTC.
guard currentCallThreadProvider.currentCallThread != thread else {
GroupCallPeekLogger.shared.info("Ignoring peek request for the current call")
logger.info("Ignoring peek request for the current call.")
return
}
guard thread.isLocalUserFullMember else {
logger.warn("Ignoring peek request for non-member thread!")
return
}
@ -114,7 +128,7 @@ public class GroupCallManager {
}()
if shouldUpdateCallModels {
self.logger.info("Applying group call PeekInfo for thread: \(thread.uniqueId) eraId: \(info.eraId ?? "(null)")")
self.logger.info("Applying group call PeekInfo for thread: \(thread.uniqueId), callId: \(info.callId?.description ?? "(null)")")
await self.databaseStorage.awaitableWrite { tx in
self.updateGroupCallModelsForPeek(
@ -125,7 +139,7 @@ public class GroupCallManager {
)
}
} else {
self.logger.info("Ignoring group call PeekInfo for thread: \(thread.uniqueId) stale eraId: \(info.eraId ?? "(null)")")
self.logger.info("Ignoring group call PeekInfo for thread: \(thread.uniqueId), stale callId: \(info.callId?.description ?? "(null)")")
}
} catch {
if error.isNetworkFailureOrTimeout {
@ -148,8 +162,7 @@ public class GroupCallManager {
triggerEventTimestamp: UInt64,
tx: SDSAnyWriteTransaction
) {
let currentEraId: String? = peekInfo.eraId
let currentCallId: UInt64? = currentEraId.map { callIdFromEra($0) }
let currentCallId: CallId? = peekInfo.callId
// Clean up any unended group calls that don't match the currently
// in-progress call.
@ -160,7 +173,6 @@ public class GroupCallManager {
)
guard
let currentEraId,
let currentCallId,
let creatorAci = peekInfo.creator.map({ Aci(fromUUID: $0) }),
let groupThreadRowId = groupThread.sqliteRowId
@ -186,7 +198,7 @@ public class GroupCallManager {
// "current" call ID. If so, we should reuse/update it and its
// interaction.
switch self.callRecordStore.fetch(
callId: currentCallId,
callId: currentCallId.rawValue,
threadRowId: groupThreadRowId,
tx: tx.asV2Write
) {
@ -212,13 +224,13 @@ public class GroupCallManager {
case .found(let interactionToUpdate):
let wasOldMessageEmpty = interactionToUpdate.joinedMemberUuids?.count == 0 && !interactionToUpdate.hasEnded
logger.info("Updating group call interaction for thread \(groupThread.uniqueId), eraId \(currentEraId). Joined member count: \(joinedMemberAcis.count)")
logger.info("Updating group call interaction for thread \(groupThread.uniqueId), callId \(currentCallId). Joined member count: \(joinedMemberAcis.count)")
self.interactionStore.updateGroupCallInteractionAcis(
groupCallInteraction: interactionToUpdate,
joinedMemberAcis: joinedMemberAcis,
creatorAci: creatorAci,
callId: currentCallId,
callId: currentCallId.rawValue,
groupThreadRowId: groupThreadRowId,
notificationScheduler: self.schedulers.main,
tx: tx.asV2Write
@ -259,7 +271,7 @@ public class GroupCallManager {
}
private func createModelsForNewGroupCall(
callId: UInt64,
callId: CallId,
joinedMemberAcis: [Aci],
creatorAci: Aci?,
triggerEventTimestamp: UInt64,
@ -277,7 +289,7 @@ public class GroupCallManager {
logger.info("Creating record for group call discovered via peek.")
_ = groupCallRecordManager.createGroupCallRecordForPeek(
callId: callId,
callId: callId.rawValue,
groupCallInteraction: newGroupCallInteraction,
groupCallInteractionRowId: interactionRowId,
groupThread: groupThread,
@ -298,18 +310,18 @@ public class GroupCallManager {
/// The interaction representing the in-progress call for the given group
/// (matching the given call ID), if any.
private func cleanUpUnendedCallMessagesAsNecessary(
currentCallId: UInt64?,
currentCallId: CallId?,
groupThread: TSGroupThread,
tx: SDSAnyWriteTransaction
) -> OWSGroupCallMessage? {
enum CallIdProvider {
case legacyEraId(callId: UInt64)
case legacyEraId(eraId: String)
case callRecord(callRecord: CallRecord)
var callId: UInt64 {
var callId: CallId {
switch self {
case .legacyEraId(let callId): return callId
case .callRecord(let callRecord): return callRecord.callId
case .legacyEraId(let eraId): return CallId(eraId: eraId)
case .callRecord(let callRecord): return CallId(callRecord.callId)
}
}
}
@ -325,7 +337,7 @@ public class GroupCallManager {
if let legacyCallInteractionEraId = groupCallInteraction.eraId {
return (
groupCallInteraction,
.legacyEraId(callId: callIdFromEra(legacyCallInteractionEraId))
.legacyEraId(eraId: legacyCallInteractionEraId)
)
} else if
let callRowId = groupCallInteraction.sqliteRowId,
@ -347,11 +359,22 @@ public class GroupCallManager {
// Any call in our database that hasn't ended yet that doesn't match the
// current call ID must have ended by definition. We do that update now.
for (unendedCallInteraction, callIdProvider) in unendedCalls {
guard callIdProvider.callId != currentCallId else {
guard
callIdProvider.callId != currentCallId,
let groupThreadRowId = groupThread.sqliteRowId
else {
continue
}
unendedCallInteraction.update(withHasEnded: true, transaction: tx)
logger.info("Marking unended group call interaction as ended for thread \(groupThread.uniqueId), callId \(callIdProvider.callId).")
interactionStore.markGroupCallInteractionAsEnded(
groupCallInteraction: unendedCallInteraction,
callId: callIdProvider.callId.rawValue,
groupThreadRowId: groupThreadRowId,
notificationScheduler: schedulers.main,
tx: tx.asV2Write
)
}
guard let currentCallId else {
@ -385,7 +408,7 @@ public class GroupCallManager {
return
}
let callId = callIdFromEra(eraId)
let callId = CallId(eraId: eraId)
guard let groupThreadRowId = groupThread.sqliteRowId else {
owsFailDebug("Missing SQLite row ID for group thread!")
@ -393,7 +416,7 @@ public class GroupCallManager {
}
switch self.callRecordStore.fetch(
callId: callId,
callId: callId.rawValue,
threadRowId: groupThreadRowId,
tx: tx.asV2Read
) {
@ -457,3 +480,32 @@ public class GroupCallManager {
)
}
}
// MARK: -
/// A wrapper around UInt64 call IDs that pre-redacts them the same way the hex
/// redaction rule would otherwise.
private struct CallId: CustomStringConvertible, Equatable {
private static let unredactedLength: Int = 3
let rawValue: UInt64
init(_ rawValue: UInt64) {
self.rawValue = rawValue
}
init(eraId: String) {
self.rawValue = callIdFromEra(eraId)
}
var description: String {
let redactedCallId = "\(rawValue)".suffix(Self.unredactedLength)
return "\(redactedCallId)"
}
}
private extension PeekInfo {
var callId: CallId? {
return eraId.map { CallId(eraId: $0) }
}
}