Try to use group changes when learning of a v2 group.

This commit is contained in:
Matthew Chen 2020-02-11 12:18:51 -03:00
parent e937fe02c7
commit bb28184289
4 changed files with 55 additions and 30 deletions

View File

@ -20,12 +20,8 @@ public class GroupV2UpdatesImpl: NSObject, GroupV2UpdatesSwift {
return SSKEnvironment.shared.messageProcessing
}
private var groupsV2: GroupsV2 {
return SSKEnvironment.shared.groupsV2
}
private var groupsV2Swift: GroupsV2Swift {
return self.groupsV2 as! GroupsV2Swift
private var groupsV2: GroupsV2Swift {
return SSKEnvironment.shared.groupsV2 as! GroupsV2Swift
}
private var tsAccountManager: TSAccountManager {
@ -305,15 +301,25 @@ public class GroupV2UpdatesImpl: NSObject, GroupV2UpdatesSwift {
return self.fetchAndApplyChangeActionsFromService(groupSecretParamsData: groupSecretParamsData,
groupUpdateMode: groupUpdateMode)
.recover { (error) throws -> Promise<TSGroupThread> in
switch error {
case GroupsV2Error.groupNotInDatabase:
// Unknown groups are handled by snapshot.
break
default:
owsFailDebug("Error: \(error)")
}
let shouldTrySnapshot = { () -> Bool in
// GroupsV2 TODO: This should not fail over in the case of networking problems.
switch error {
case GroupsV2Error.groupNotInDatabase:
// Unknown groups are handled by snapshot.
return true
case GroupsV2Error.unauthorized:
// We can recover from some auth edge cases
// using a snapshot.
return true
default:
owsFailDebug("Error: \(error)")
return false
}
}()
// GroupsV2 TODO: This should not fail over in the case of networking problems.
guard shouldTrySnapshot else {
throw error
}
// Failover to applying latest snapshot.
return self.fetchAndApplyCurrentGroupV2SnapshotFromService(groupSecretParamsData: groupSecretParamsData,
@ -362,7 +368,7 @@ public class GroupV2UpdatesImpl: NSObject, GroupV2UpdatesSwift {
let updatedGroupThread = try GroupManager.updateExistingGroupThreadInDatabaseAndCreateInfoMessage(groupThread: groupThread,
newGroupModel: changedGroupModel.newGroupModel,
groupUpdateSourceAddress: groupUpdateSourceAddress,
transaction: transaction).groupThread
transaction: transaction).groupThread
GroupManager.storeProfileKeysFromGroupProtos(changedGroupModel.profileKeys)
@ -377,9 +383,17 @@ public class GroupV2UpdatesImpl: NSObject, GroupV2UpdatesSwift {
private func fetchAndApplyChangeActionsFromService(groupSecretParamsData: Data,
groupUpdateMode: GroupUpdateMode) -> Promise<TSGroupThread> {
return firstly {
groupsV2Swift.fetchGroupChangeActions(groupSecretParamsData: groupSecretParamsData)
}.then(on: DispatchQueue.global()) { (groupChanges) throws -> Promise<TSGroupThread> in
return firstly { () -> Promise<[GroupV2Change]> in
var firstKnownRevision: UInt32?
switch groupUpdateMode {
case .upToSpecificRevisionImmediately(let upToRevision):
firstKnownRevision = upToRevision
default:
break
}
return self.groupsV2.fetchGroupChangeActions(groupSecretParamsData: groupSecretParamsData,
firstKnownRevision: firstKnownRevision)
}.then(on: DispatchQueue.global()) { (groupChanges: [GroupV2Change]) throws -> Promise<TSGroupThread> in
let groupId = try self.groupsV2.groupId(forGroupSecretParamsData: groupSecretParamsData)
return self.tryToApplyGroupChangesFromService(groupId: groupId,
groupChanges: groupChanges,
@ -462,7 +476,7 @@ public class GroupV2UpdatesImpl: NSObject, GroupV2UpdatesSwift {
groupThread = try GroupManager.updateExistingGroupThreadInDatabaseAndCreateInfoMessage(groupThread: groupThread,
newGroupModel: newGroupModel,
groupUpdateSourceAddress: groupUpdateSourceAddress,
transaction: transaction).groupThread
transaction: transaction).groupThread
}
return groupThread
@ -474,7 +488,7 @@ public class GroupV2UpdatesImpl: NSObject, GroupV2UpdatesSwift {
private func fetchAndApplyCurrentGroupV2SnapshotFromService(groupSecretParamsData: Data,
groupUpdateMode: GroupUpdateMode) -> Promise<TSGroupThread> {
return firstly {
self.groupsV2Swift.fetchCurrentGroupV2Snapshot(groupSecretParamsData: groupSecretParamsData)
self.groupsV2.fetchCurrentGroupV2Snapshot(groupSecretParamsData: groupSecretParamsData)
}.then(on: .global()) { groupV2Snapshot in
return self.tryToApplyCurrentGroupV2SnapshotFromService(groupV2Snapshot: groupV2Snapshot,
groupUpdateMode: groupUpdateMode)
@ -502,9 +516,9 @@ public class GroupV2UpdatesImpl: NSObject, GroupV2UpdatesSwift {
// author(s) of changes reflected in the snapshot.
let groupUpdateSourceAddress: SignalServiceAddress? = nil
let result = try GroupManager.tryToUpsertExistingGroupThreadInDatabaseAndCreateInfoMessage(newGroupModel: newGroupModel,
groupUpdateSourceAddress: groupUpdateSourceAddress,
canInsert: true,
transaction: transaction)
groupUpdateSourceAddress: groupUpdateSourceAddress,
canInsert: true,
transaction: transaction)
GroupManager.storeProfileKeysFromGroupProtos(groupV2Snapshot.profileKeys)

View File

@ -271,7 +271,8 @@ public class GroupsV2Impl: NSObject, GroupsV2Swift {
// MARK: - Fetch Group Change Actions
public func fetchGroupChangeActions(groupSecretParamsData: Data) -> Promise<[GroupV2Change]> {
public func fetchGroupChangeActions(groupSecretParamsData: Data,
firstKnownRevision: UInt32?) -> Promise<[GroupV2Change]> {
guard let localUuid = tsAccountManager.localUuid else {
return Promise(error: OWSAssertionError("Missing localUuid."))
}
@ -282,19 +283,25 @@ public class GroupsV2Impl: NSObject, GroupsV2Swift {
}.then(on: DispatchQueue.global()) { (groupId: Data, groupV2Params: GroupV2Params) -> Promise<[GroupV2Change]> in
return self.fetchGroupChangeActions(groupId: groupId,
groupV2Params: groupV2Params,
localUuid: localUuid)
localUuid: localUuid,
firstKnownRevision: firstKnownRevision)
}
}
private func fetchGroupChangeActions(groupId: Data,
groupV2Params: GroupV2Params,
localUuid: UUID) -> Promise<[GroupV2Change]> {
localUuid: UUID,
firstKnownRevision: UInt32?) -> Promise<[GroupV2Change]> {
let requestBuilder: RequestBuilder = { (authCredential, sessionManager) in
return DispatchQueue.global().async(.promise) { () -> NSURLRequest in
let fromRevision = try self.databaseStorage.read { (transaction) throws -> UInt32 in
guard let groupThread = TSGroupThread.fetch(groupId: groupId, transaction: transaction) else {
// This probably isn't an error and will be handled upstream.
if let firstKnownRevision = firstKnownRevision {
Logger.info("Group not in database, using first known revision.")
return firstKnownRevision
}
throw GroupsV2Error.groupNotInDatabase
}
guard groupThread.groupModel.groupsVersion == .V2 else {

View File

@ -589,8 +589,8 @@ class IncomingGroupsV2MessageQueue: NSObject {
let groupUpdateMode = GroupUpdateMode.upToSpecificRevisionImmediately(upToRevision: groupContext.revision)
return firstly {
groupV2UpdatesSwift.tryToRefreshV2GroupThreadWithThrottling(groupId: groupContextInfo.groupId,
groupSecretParamsData: groupContextInfo.groupSecretParamsData,
groupUpdateMode: groupUpdateMode)
groupSecretParamsData: groupContextInfo.groupSecretParamsData,
groupUpdateMode: groupUpdateMode)
}.map(on: .global()) { (_) in
return UpdateOutcome.successShouldProcess
}.recover(on: .global()) { error -> Guarantee<UpdateOutcome> in

View File

@ -55,7 +55,8 @@ public protocol GroupsV2Swift: GroupsV2 {
func fetchCurrentGroupV2Snapshot(groupSecretParamsData: Data) -> Promise<GroupV2Snapshot>
func fetchGroupChangeActions(groupSecretParamsData: Data) -> Promise<[GroupV2Change]>
func fetchGroupChangeActions(groupSecretParamsData: Data,
firstKnownRevision: UInt32?) -> Promise<[GroupV2Change]>
func buildChangeSet(oldGroupModel: TSGroupModel,
newGroupModel: TSGroupModel,
@ -94,6 +95,8 @@ public enum GroupUpdateMode {
// * Group update should halt at a specific revision.
// * Group update _should not_ block on message processing.
// * Group update _should not_ be throttled.
//
// upToRevision is inclusive.
case upToSpecificRevisionImmediately(upToRevision: UInt32)
// * Group update should continue until current revision.
// * Group update _should_ block on message processing.
@ -222,7 +225,8 @@ public class MockGroupsV2: NSObject, GroupsV2, GroupsV2Swift {
owsFail("Not implemented.")
}
public func fetchGroupChangeActions(groupSecretParamsData: Data) -> Promise<[GroupV2Change]> {
public func fetchGroupChangeActions(groupSecretParamsData: Data,
firstKnownRevision: UInt32?) -> Promise<[GroupV2Change]> {
owsFail("Not implemented.")
}