Merge branch 'charlesmchen/removePrimaryStorage4'
This commit is contained in:
commit
8ee5437fde
@ -53,7 +53,6 @@ NSString *NSStringForPerMessageExpirationState(PerMessageExpirationState value);
|
||||
@class TSAttachmentStream;
|
||||
@class TSInteraction;
|
||||
@class TSThread;
|
||||
@class YapDatabaseReadTransaction;
|
||||
|
||||
@interface ConversationMediaAlbumItem : NSObject
|
||||
|
||||
|
||||
@ -720,14 +720,11 @@ NSString *NSStringForPerMessageExpirationState(PerMessageExpirationState cellTyp
|
||||
return;
|
||||
}
|
||||
|
||||
if (transaction.transitional_yapReadTransaction != nil) {
|
||||
if (message.contactShare) {
|
||||
self.contactShare =
|
||||
[[ContactShareViewModel alloc] initWithContactShareRecord:message.contactShare
|
||||
transaction:transaction.transitional_yapReadTransaction];
|
||||
self.messageCellType = OWSMessageCellType_ContactShare;
|
||||
return;
|
||||
}
|
||||
if (message.contactShare) {
|
||||
self.contactShare =
|
||||
[[ContactShareViewModel alloc] initWithContactShareRecord:message.contactShare transaction:transaction];
|
||||
self.messageCellType = OWSMessageCellType_ContactShare;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for stickers _before_ media or quoted reply handling;
|
||||
|
||||
@ -3625,31 +3625,25 @@ typedef OWSContact * (^OWSContactBlock)(SDSAnyWriteTransaction *transaction);
|
||||
verificationState:OWSVerificationStateNoLongerVerified
|
||||
isLocalChange:NO]];
|
||||
|
||||
if (transaction.transitional_yapWriteTransaction) {
|
||||
[result addObject:[TSErrorMessage missingSessionWithEnvelope:[self createEnvelopeForThread:thread]
|
||||
withTransaction:transaction.transitional_yapWriteTransaction]];
|
||||
[result addObject:[TSErrorMessage
|
||||
invalidKeyExceptionWithEnvelope:[self createEnvelopeForThread:thread]
|
||||
withTransaction:transaction.transitional_yapWriteTransaction]];
|
||||
[result addObject:[TSErrorMessage invalidVersionWithEnvelope:[self createEnvelopeForThread:thread]
|
||||
withTransaction:transaction.transitional_yapWriteTransaction]];
|
||||
[result
|
||||
addObject:[TSErrorMessage corruptedMessageWithEnvelope:[self createEnvelopeForThread:thread]
|
||||
withTransaction:transaction.transitional_yapWriteTransaction]];
|
||||
[result addObject:[TSErrorMessage missingSessionWithEnvelope:[self createEnvelopeForThread:thread]
|
||||
withTransaction:transaction]];
|
||||
[result addObject:[TSErrorMessage invalidKeyExceptionWithEnvelope:[self createEnvelopeForThread:thread]
|
||||
withTransaction:transaction]];
|
||||
[result addObject:[TSErrorMessage invalidVersionWithEnvelope:[self createEnvelopeForThread:thread]
|
||||
withTransaction:transaction]];
|
||||
[result addObject:[TSErrorMessage corruptedMessageWithEnvelope:[self createEnvelopeForThread:thread]
|
||||
withTransaction:transaction]];
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
TSInvalidIdentityKeyReceivingErrorMessage *_Nullable blockingSNChangeMessage =
|
||||
[TSInvalidIdentityKeyReceivingErrorMessage
|
||||
untrustedKeyWithEnvelope:[self createEnvelopeForThread:thread]
|
||||
withTransaction:transaction.transitional_yapWriteTransaction];
|
||||
TSInvalidIdentityKeyReceivingErrorMessage *_Nullable blockingSNChangeMessage =
|
||||
[TSInvalidIdentityKeyReceivingErrorMessage untrustedKeyWithEnvelope:[self createEnvelopeForThread:thread]
|
||||
withTransaction:transaction];
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
|
||||
OWSAssertDebug(blockingSNChangeMessage);
|
||||
[result addObject:blockingSNChangeMessage];
|
||||
} else {
|
||||
OWSFailDebug(@"failure: not yet implemented for GRDB");
|
||||
}
|
||||
OWSAssertDebug(blockingSNChangeMessage);
|
||||
[result addObject:blockingSNChangeMessage];
|
||||
|
||||
// MJK TODO - should be safe to remove this senderTimestamp
|
||||
[result addObject:[[TSErrorMessage alloc]
|
||||
initWithTimestamp:[NSDate ows_millisecondTimeStamp]
|
||||
|
||||
@ -219,8 +219,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
NSString *fileName = filePath.lastPathComponent;
|
||||
|
||||
__block BOOL success;
|
||||
[OWSPrimaryStorage.sharedManager.newDatabaseConnection
|
||||
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.databaseStorage
|
||||
writeWithBlock:^(SDSAnyWriteTransaction *transaction) {
|
||||
NSError *error;
|
||||
success = [[NSFileManager defaultManager] copyItemAtPath:OWSPrimaryStorage.databaseFilePath
|
||||
toPath:filePath
|
||||
|
||||
@ -523,14 +523,14 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
+ (void)hallucinateTwinGroup:(TSGroupThread *)groupThread
|
||||
{
|
||||
__block TSGroupThread *thread;
|
||||
[OWSPrimaryStorage.dbReadWriteConnection
|
||||
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
|
||||
[self.databaseStorage
|
||||
writeWithBlock:^(SDSAnyWriteTransaction *transaction) {
|
||||
TSGroupModel *groupModel =
|
||||
[[TSGroupModel alloc] initWithTitle:[groupThread.groupModel.groupName stringByAppendingString:@" Copy"]
|
||||
members:groupThread.groupModel.groupMembers
|
||||
image:groupThread.groupModel.groupImage
|
||||
groupId:[Randomness generateRandomBytes:kGroupIdLength]];
|
||||
thread = [TSGroupThread getOrCreateThreadWithGroupModel:groupModel transaction:transaction.asAnyWrite];
|
||||
thread = [TSGroupThread getOrCreateThreadWithGroupModel:groupModel transaction:transaction];
|
||||
}];
|
||||
OWSAssertDebug(thread);
|
||||
|
||||
@ -559,13 +559,12 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
[recipientAddresses addObject:self.tsAccountManager.localAddress];
|
||||
|
||||
__block TSGroupThread *thread;
|
||||
[OWSPrimaryStorage.dbReadWriteConnection readWriteWithBlock:^(
|
||||
YapDatabaseReadWriteTransaction *_Nonnull transaction) {
|
||||
[self.databaseStorage writeWithBlock:^(SDSAnyWriteTransaction *transaction) {
|
||||
TSGroupModel *groupModel = [[TSGroupModel alloc] initWithTitle:NSUUID.UUID.UUIDString
|
||||
members:recipientAddresses
|
||||
image:nil
|
||||
groupId:[Randomness generateRandomBytes:kGroupIdLength]];
|
||||
thread = [TSGroupThread getOrCreateThreadWithGroupModel:groupModel transaction:transaction.asAnyWrite];
|
||||
thread = [TSGroupThread getOrCreateThreadWithGroupModel:groupModel transaction:transaction];
|
||||
}];
|
||||
OWSAssertDebug(thread);
|
||||
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class ThreadViewModel;
|
||||
@class YapDatabaseReadTransaction;
|
||||
|
||||
@interface HomeViewCell : UITableViewCell
|
||||
|
||||
|
||||
@ -1510,10 +1510,9 @@ NSString *const kArchiveButtonPseudoGroup = @"kArchiveButtonPseudoGroup";
|
||||
if (![[uiDatabaseConnection ext:TSThreadDatabaseViewExtensionName] hasChangesForGroup:self.currentGrouping
|
||||
inNotifications:notifications]) {
|
||||
|
||||
[uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
SDSAnyReadTransaction *anyReadTransaction = transaction.asAnyRead;
|
||||
[self.databaseStorage uiReadWithBlock:^(SDSAnyReadTransaction *transaction) {
|
||||
[self.threadMapping updateSwallowingErrorsWithIsViewingArchive:self.isViewingArchive
|
||||
transaction:anyReadTransaction];
|
||||
transaction:transaction];
|
||||
}];
|
||||
[self updateViewState];
|
||||
|
||||
|
||||
@ -20,6 +20,14 @@ protocol MessageDetailViewDelegate: AnyObject {
|
||||
@objc
|
||||
class MessageDetailViewController: OWSViewController {
|
||||
|
||||
// MARK: - Dependencies
|
||||
|
||||
private var databaseStorage: SDSDatabaseStorage {
|
||||
return SDSDatabaseStorage.shared
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
@objc
|
||||
weak var delegate: MessageDetailViewDelegate?
|
||||
|
||||
@ -424,13 +432,13 @@ class MessageDetailViewController: OWSViewController {
|
||||
return rows
|
||||
}
|
||||
|
||||
private func fetchAttachment(transaction: YapDatabaseReadTransaction) -> TSAttachment? {
|
||||
private func fetchAttachment(transaction: SDSAnyReadTransaction) -> TSAttachment? {
|
||||
// TODO: Support multi-image messages.
|
||||
guard let attachmentId = message.attachmentIds.firstObject as? String else {
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let attachment = TSAttachment.anyFetch(uniqueId: attachmentId, transaction: transaction.asAnyRead) else {
|
||||
guard let attachment = TSAttachment.anyFetch(uniqueId: attachmentId, transaction: transaction) else {
|
||||
Logger.warn("Missing attachment. Was it deleted?")
|
||||
return nil
|
||||
}
|
||||
@ -562,12 +570,12 @@ class MessageDetailViewController: OWSViewController {
|
||||
|
||||
AssertIsOnMainThread()
|
||||
|
||||
try self.uiDatabaseConnection.read { transaction in
|
||||
try databaseStorage.uiReadThrows { transaction in
|
||||
guard let uniqueId = self.message.uniqueId else {
|
||||
Logger.error("Message is missing uniqueId.")
|
||||
return
|
||||
}
|
||||
guard let newMessage = TSInteraction.anyFetch(uniqueId: uniqueId, transaction: transaction.asAnyRead) as? TSMessage else {
|
||||
guard let newMessage = TSInteraction.anyFetch(uniqueId: uniqueId, transaction: transaction) as? TSMessage else {
|
||||
Logger.error("Message was deleted")
|
||||
throw DetailViewError.messageWasDeleted
|
||||
}
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
#import <SignalServiceKit/AppContext.h>
|
||||
#import <SignalServiceKit/MimeTypeUtil.h>
|
||||
#import <SignalServiceKit/OWSPrimaryStorage.h>
|
||||
#import <SignalServiceKit/SignalServiceKit-Swift.h>
|
||||
#import <SignalServiceKit/TSAccountManager.h>
|
||||
#import <SignalServiceKit/TSContactThread.h>
|
||||
#import <sys/sysctl.h>
|
||||
@ -597,9 +598,8 @@ typedef void (^DebugLogUploadFailure)(DebugLogUploader *uploader, NSError *error
|
||||
|
||||
DispatchMainThreadSafe(^{
|
||||
__block TSThread *thread = nil;
|
||||
[OWSPrimaryStorage.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
thread = [TSContactThread getOrCreateThreadWithContactAddress:recipientAddress
|
||||
transaction:transaction.asAnyWrite];
|
||||
[self.databaseStorage writeWithBlock:^(SDSAnyWriteTransaction *transaction) {
|
||||
thread = [TSContactThread getOrCreateThreadWithContactAddress:recipientAddress transaction:transaction];
|
||||
}];
|
||||
[self.databaseStorage readWithBlock:^(SDSAnyReadTransaction *transaction) {
|
||||
[ThreadUtil enqueueMessageWithText:url.absoluteString
|
||||
|
||||
@ -47,6 +47,15 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@implementation SelectThreadViewController
|
||||
|
||||
#pragma mark - Dependencies
|
||||
|
||||
- (SDSDatabaseStorage *)databaseStorage
|
||||
{
|
||||
return SDSDatabaseStorage.shared;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (void)loadView
|
||||
{
|
||||
[super loadView];
|
||||
@ -209,12 +218,11 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
if (!cell.hasAccessoryText) {
|
||||
// Don't add a disappearing messages indicator if we've already added a "blocked" label.
|
||||
__block OWSDisappearingMessagesConfiguration *disappearingMessagesConfiguration;
|
||||
[self.uiDatabaseConnection
|
||||
readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
|
||||
disappearingMessagesConfiguration = [OWSDisappearingMessagesConfiguration
|
||||
anyFetchWithUniqueId:thread.uniqueId
|
||||
transaction:transaction.asAnyRead];
|
||||
}];
|
||||
[strongSelf.databaseStorage uiReadWithBlock:^(SDSAnyReadTransaction *transaction) {
|
||||
disappearingMessagesConfiguration =
|
||||
[OWSDisappearingMessagesConfiguration anyFetchWithUniqueId:thread.uniqueId
|
||||
transaction:transaction];
|
||||
}];
|
||||
|
||||
if (disappearingMessagesConfiguration && disappearingMessagesConfiguration.isEnabled) {
|
||||
DisappearingTimerConfigurationView *disappearingTimerConfigurationView =
|
||||
@ -327,9 +335,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
}
|
||||
|
||||
__block TSThread *thread = nil;
|
||||
[OWSPrimaryStorage.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.databaseStorage writeWithBlock:^(SDSAnyWriteTransaction *transaction) {
|
||||
thread = [TSContactThread getOrCreateThreadWithContactAddress:signalAccount.recipientAddress
|
||||
transaction:transaction.asAnyWrite];
|
||||
transaction:transaction];
|
||||
}];
|
||||
OWSAssertDebug(thread);
|
||||
|
||||
|
||||
@ -40,8 +40,8 @@ public class ContactShareViewModel: NSObject {
|
||||
}
|
||||
|
||||
@objc
|
||||
public convenience init(contactShareRecord: OWSContact, transaction: YapDatabaseReadTransaction) {
|
||||
if let avatarAttachment = contactShareRecord.avatarAttachment(with: transaction.asAnyRead) as? TSAttachmentStream {
|
||||
public convenience init(contactShareRecord: OWSContact, transaction: SDSAnyReadTransaction) {
|
||||
if let avatarAttachment = contactShareRecord.avatarAttachment(with: transaction) as? TSAttachmentStream {
|
||||
self.init(contactShareRecord: contactShareRecord, avatarImageData: avatarAttachment.validStillImageData())
|
||||
} else {
|
||||
self.init(contactShareRecord: contactShareRecord, avatarImageData: nil)
|
||||
|
||||
@ -8,8 +8,8 @@
|
||||
#import "UIFont+OWS.h"
|
||||
#import "UIView+OWS.h"
|
||||
#import <SignalMessaging/SignalMessaging-Swift.h>
|
||||
#import <SignalServiceKit/OWSPrimaryStorage.h>
|
||||
#import <SignalServiceKit/SignalAccount.h>
|
||||
#import <SignalServiceKit/SignalServiceKit-Swift.h>
|
||||
#import <SignalServiceKit/TSContactThread.h>
|
||||
#import <SignalServiceKit/TSGroupThread.h>
|
||||
#import <SignalServiceKit/TSThread.h>
|
||||
@ -53,11 +53,9 @@ const CGFloat kContactCellAvatarTextMargin = 12;
|
||||
return Environment.shared.contactsManager;
|
||||
}
|
||||
|
||||
- (OWSPrimaryStorage *)primaryStorage
|
||||
- (SDSDatabaseStorage *)databaseStorage
|
||||
{
|
||||
OWSAssertDebug(SSKEnvironment.shared.primaryStorage);
|
||||
|
||||
return SSKEnvironment.shared.primaryStorage;
|
||||
return SDSDatabaseStorage.shared;
|
||||
}
|
||||
|
||||
- (TSAccountManager *)tsAccountManager
|
||||
@ -129,8 +127,8 @@ const CGFloat kContactCellAvatarTextMargin = 12;
|
||||
|
||||
self.address = address;
|
||||
|
||||
[self.primaryStorage.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
self.thread = [TSContactThread getThreadWithContactAddress:address transaction:transaction.asAnyRead];
|
||||
[self.databaseStorage readWithBlock:^(SDSAnyReadTransaction *transaction) {
|
||||
self.thread = [TSContactThread getThreadWithContactAddress:address transaction:transaction];
|
||||
}];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
|
||||
@ -742,50 +742,15 @@ typedef void (^BuildOutgoingMessageCompletionBlock)(TSOutgoingMessage *savedMess
|
||||
{
|
||||
OWSLogInfo(@"");
|
||||
|
||||
[OWSPrimaryStorage.sharedManager.newDatabaseConnection
|
||||
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self removeAllObjectsInCollection:[TSThread collection] class:[TSThread class] transaction:transaction];
|
||||
[self removeAllObjectsInCollection:[TSInteraction collection]
|
||||
class:[TSInteraction class]
|
||||
transaction:transaction];
|
||||
[self removeAllObjectsInCollection:[TSAttachment collection]
|
||||
class:[TSAttachment class]
|
||||
transaction:transaction];
|
||||
[self removeAllObjectsInCollection:[SignalRecipient collection]
|
||||
class:[SignalRecipient class]
|
||||
transaction:transaction];
|
||||
}];
|
||||
[self.databaseStorage writeWithBlock:^(SDSAnyWriteTransaction *transaction) {
|
||||
[TSThread anyRemoveAllWithInstantationWithTransaction:transaction];
|
||||
[TSInteraction anyRemoveAllWithInstantationWithTransaction:transaction];
|
||||
[TSAttachment anyRemoveAllWithInstantationWithTransaction:transaction];
|
||||
[SignalRecipient anyRemoveAllWithInstantationWithTransaction:transaction];
|
||||
}];
|
||||
[TSAttachmentStream deleteAttachments];
|
||||
}
|
||||
|
||||
+ (void)removeAllObjectsInCollection:(NSString *)collection
|
||||
class:(Class) class
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction {
|
||||
OWSAssertDebug(collection.length > 0);
|
||||
OWSAssertDebug(class);
|
||||
OWSAssertDebug(transaction);
|
||||
|
||||
NSArray<NSString *> *_Nullable uniqueIds = [transaction allKeysInCollection:collection];
|
||||
if (!uniqueIds) {
|
||||
OWSFailDebug(@"couldn't load uniqueIds for collection: %@.", collection);
|
||||
return;
|
||||
}
|
||||
OWSLogInfo(@"Deleting %lu objects from: %@", (unsigned long)uniqueIds.count, collection);
|
||||
NSUInteger count = 0;
|
||||
for (NSString *uniqueId in uniqueIds) {
|
||||
// We need to fetch each object, since [TSYapDatabaseObject removeWithTransaction:] sometimes does important
|
||||
// work.
|
||||
TSYapDatabaseObject *_Nullable object = [class fetchObjectWithUniqueID:uniqueId transaction:transaction];
|
||||
if (!object) {
|
||||
OWSFailDebug(@"couldn't load object for deletion: %@.", collection);
|
||||
continue;
|
||||
}
|
||||
[object removeWithTransaction:transaction];
|
||||
count++;
|
||||
};
|
||||
OWSLogInfo(@"Deleted %lu/%lu objects from: %@", (unsigned long)count, (unsigned long)uniqueIds.count, collection);
|
||||
}
|
||||
|
||||
#pragma mark - Find Content
|
||||
|
||||
+ (nullable TSInteraction *)findInteractionInThreadByTimestamp:(uint64_t)timestamp
|
||||
|
||||
@ -37,6 +37,9 @@ NS_SWIFT_NAME(init(uniqueId:durationSeconds:enabled:));
|
||||
@property (nonatomic, readonly) NSUInteger durationIndex;
|
||||
@property (nonatomic, readonly) NSString *durationString;
|
||||
@property (nonatomic, readonly) BOOL dictionaryValueDidChange;
|
||||
|
||||
// GRDB TODO: We might be able to find a better way to avoid saving defaults
|
||||
// than isNewRecord.
|
||||
@property (readonly, getter=isNewRecord) BOOL newRecord;
|
||||
|
||||
+ (instancetype)fetchOrBuildDefaultWithThreadId:(NSString *)threadId transaction:(SDSAnyReadTransaction *)transaction;
|
||||
|
||||
@ -159,6 +159,23 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
- (void)saveWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
[super saveWithTransaction:transaction];
|
||||
|
||||
self.originalDictionaryValue = [self dictionaryValue];
|
||||
self.newRecord = NO;
|
||||
}
|
||||
|
||||
- (void)anyDidInsertWithTransaction:(SDSAnyWriteTransaction *)transaction
|
||||
{
|
||||
[super anyDidInsertWithTransaction:transaction];
|
||||
|
||||
self.originalDictionaryValue = [self dictionaryValue];
|
||||
self.newRecord = NO;
|
||||
}
|
||||
|
||||
- (void)anyDidUpdateWithTransaction:(SDSAnyWriteTransaction *)transaction
|
||||
{
|
||||
[super anyDidUpdateWithTransaction:transaction];
|
||||
|
||||
self.originalDictionaryValue = [self dictionaryValue];
|
||||
self.newRecord = NO;
|
||||
}
|
||||
|
||||
@ -291,12 +291,32 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
}];
|
||||
}
|
||||
|
||||
// TODO: We could add a similar check to the GRDB insert logic.
|
||||
- (void)ydb_saveWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
[self checkForStreamOverwrite:transaction.asAnyRead];
|
||||
|
||||
[super ydb_saveWithTransaction:transaction];
|
||||
}
|
||||
|
||||
- (void)anyWillInsertWithTransaction:(SDSAnyWriteTransaction *)transaction
|
||||
{
|
||||
[super anyWillInsertWithTransaction:transaction];
|
||||
|
||||
[self checkForStreamOverwrite:transaction];
|
||||
}
|
||||
|
||||
- (void)anyWillUpdateWithTransaction:(SDSAnyWriteTransaction *)transaction
|
||||
{
|
||||
[super anyWillUpdateWithTransaction:transaction];
|
||||
|
||||
[self checkForStreamOverwrite:transaction];
|
||||
}
|
||||
|
||||
- (void)checkForStreamOverwrite:(SDSAnyReadTransaction *)transaction
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (self.uniqueId.length > 0) {
|
||||
id _Nullable oldObject = [transaction objectForKey:self.uniqueId inCollection:TSAttachment.collection];
|
||||
TSAttachment *_Nullable oldObject = [TSAttachment anyFetchWithUniqueId:self.uniqueId transaction:transaction];
|
||||
if ([oldObject isKindOfClass:[TSAttachmentStream class]]) {
|
||||
OWSFailDebug(@"We should never overwrite a TSAttachmentStream with a TSAttachmentPointer.");
|
||||
}
|
||||
@ -304,8 +324,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
OWSFailDebug(@"Missing uniqueId.");
|
||||
}
|
||||
#endif
|
||||
|
||||
[super ydb_saveWithTransaction:transaction];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@ -7,7 +7,6 @@
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class SDSAnyReadTransaction;
|
||||
@class YapDatabaseReadTransaction;
|
||||
|
||||
@interface OWSSyncGroupsMessage : OWSOutgoingSyncMessage
|
||||
|
||||
|
||||
@ -97,16 +97,16 @@ NS_SWIFT_NAME(init(uniqueId:receivedAtTimestamp:sortId:timestamp:uniqueThreadId:
|
||||
// --- CODE GENERATION MARKER
|
||||
|
||||
+ (instancetype)corruptedMessageWithEnvelope:(SSKProtoEnvelope *)envelope
|
||||
withTransaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
withTransaction:(SDSAnyWriteTransaction *)transaction;
|
||||
|
||||
+ (instancetype)invalidVersionWithEnvelope:(SSKProtoEnvelope *)envelope
|
||||
withTransaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
withTransaction:(SDSAnyWriteTransaction *)transaction;
|
||||
|
||||
+ (instancetype)invalidKeyExceptionWithEnvelope:(SSKProtoEnvelope *)envelope
|
||||
withTransaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
withTransaction:(SDSAnyWriteTransaction *)transaction;
|
||||
|
||||
+ (instancetype)missingSessionWithEnvelope:(SSKProtoEnvelope *)envelope
|
||||
withTransaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
withTransaction:(SDSAnyWriteTransaction *)transaction;
|
||||
|
||||
+ (instancetype)nonblockingIdentityChangeInThread:(TSThread *)thread address:(SignalServiceAddress *)address;
|
||||
|
||||
|
||||
@ -10,7 +10,6 @@
|
||||
#import "TSErrorMessage_privateConstructor.h"
|
||||
#import <SignalCoreKit/NSDate+OWS.h>
|
||||
#import <SignalServiceKit/SignalServiceKit-Swift.h>
|
||||
#import <YapDatabase/YapDatabaseConnection.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@ -138,11 +137,11 @@ NSUInteger TSErrorMessageSchemaVersion = 2;
|
||||
}
|
||||
|
||||
- (instancetype)initWithEnvelope:(SSKProtoEnvelope *)envelope
|
||||
withTransaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
withTransaction:(SDSAnyWriteTransaction *)transaction
|
||||
failedMessageType:(TSErrorMessageType)errorMessageType
|
||||
{
|
||||
TSContactThread *contactThread = [TSContactThread getOrCreateThreadWithContactAddress:envelope.sourceAddress
|
||||
transaction:transaction.asAnyWrite];
|
||||
TSContactThread *contactThread =
|
||||
[TSContactThread getOrCreateThreadWithContactAddress:envelope.sourceAddress transaction:transaction];
|
||||
|
||||
// Legit usage of senderTimestamp. We don't actually currently surface it in the UI, but it serves as
|
||||
// a reference to the envelope which we failed to process.
|
||||
@ -262,7 +261,7 @@ perMessageExpirationDurationSeconds:perMessageExpirationDurationSeconds
|
||||
}
|
||||
|
||||
+ (instancetype)corruptedMessageWithEnvelope:(SSKProtoEnvelope *)envelope
|
||||
withTransaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
withTransaction:(SDSAnyWriteTransaction *)transaction
|
||||
{
|
||||
return [[self alloc] initWithEnvelope:envelope
|
||||
withTransaction:transaction
|
||||
@ -270,7 +269,7 @@ perMessageExpirationDurationSeconds:perMessageExpirationDurationSeconds
|
||||
}
|
||||
|
||||
+ (instancetype)invalidVersionWithEnvelope:(SSKProtoEnvelope *)envelope
|
||||
withTransaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
withTransaction:(SDSAnyWriteTransaction *)transaction
|
||||
{
|
||||
return [[self alloc] initWithEnvelope:envelope
|
||||
withTransaction:transaction
|
||||
@ -278,7 +277,7 @@ perMessageExpirationDurationSeconds:perMessageExpirationDurationSeconds
|
||||
}
|
||||
|
||||
+ (instancetype)invalidKeyExceptionWithEnvelope:(SSKProtoEnvelope *)envelope
|
||||
withTransaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
withTransaction:(SDSAnyWriteTransaction *)transaction
|
||||
{
|
||||
return [[self alloc] initWithEnvelope:envelope
|
||||
withTransaction:transaction
|
||||
@ -286,7 +285,7 @@ perMessageExpirationDurationSeconds:perMessageExpirationDurationSeconds
|
||||
}
|
||||
|
||||
+ (instancetype)missingSessionWithEnvelope:(SSKProtoEnvelope *)envelope
|
||||
withTransaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
withTransaction:(SDSAnyWriteTransaction *)transaction
|
||||
{
|
||||
return
|
||||
[[self alloc] initWithEnvelope:envelope withTransaction:transaction failedMessageType:TSErrorMessageNoSession];
|
||||
|
||||
@ -106,19 +106,6 @@ NS_SWIFT_NAME(init(uniqueId:receivedAtTimestamp:sortId:timestamp:uniqueThreadId:
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/*
|
||||
* Find a message matching the senderId and timestamp, if any.
|
||||
*
|
||||
* @param authorId
|
||||
* Signal ID (i.e. e164) of the user who sent the message
|
||||
* @params timestamp
|
||||
* When the message was created in milliseconds since epoch
|
||||
*
|
||||
*/
|
||||
+ (nullable instancetype)findMessageWithAddress:(SignalServiceAddress *)address
|
||||
timestamp:(uint64_t)timestamp
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
|
||||
// This will be 0 for messages created before we were tracking sourceDeviceId
|
||||
@property (nonatomic, readonly) UInt32 sourceDeviceId;
|
||||
|
||||
|
||||
@ -13,7 +13,6 @@
|
||||
#import "TSGroupThread.h"
|
||||
#import <SignalCoreKit/NSDate+OWS.h>
|
||||
#import <SignalServiceKit/SignalServiceKit-Swift.h>
|
||||
#import <YapDatabase/YapDatabaseConnection.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@ -165,46 +164,15 @@ perMessageExpirationDurationSeconds:perMessageExpirationDurationSeconds
|
||||
|
||||
// --- CODE GENERATION MARKER
|
||||
|
||||
+ (nullable instancetype)findMessageWithAddress:(SignalServiceAddress *)address
|
||||
timestamp:(uint64_t)timestamp
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
OWSAssertDebug(transaction);
|
||||
|
||||
__block TSIncomingMessage *foundMessage;
|
||||
// In theory we could build a new secondaryIndex for (authorId,timestamp), but in practice there should
|
||||
// be *very* few (millisecond) timestamps with multiple authors.
|
||||
[TSDatabaseSecondaryIndexes
|
||||
enumerateMessagesWithTimestamp:timestamp
|
||||
withBlock:^(NSString *collection, NSString *key, BOOL *stop) {
|
||||
TSInteraction *_Nullable interaction =
|
||||
[TSInteraction anyFetchWithUniqueId:key transaction:transaction.asAnyRead];
|
||||
if ([interaction isKindOfClass:[TSIncomingMessage class]]) {
|
||||
TSIncomingMessage *message = (TSIncomingMessage *)interaction;
|
||||
|
||||
OWSAssertDebug(message.authorAddress.isValid);
|
||||
|
||||
if ([message.authorAddress isEqualToAddress:address]) {
|
||||
foundMessage = message;
|
||||
}
|
||||
}
|
||||
}
|
||||
usingTransaction:transaction];
|
||||
|
||||
return foundMessage;
|
||||
}
|
||||
|
||||
|
||||
- (OWSInteractionType)interactionType
|
||||
{
|
||||
return OWSInteractionType_IncomingMessage;
|
||||
}
|
||||
|
||||
- (BOOL)shouldStartExpireTimerWithTransaction:(YapDatabaseReadTransaction *)transaction
|
||||
- (BOOL)shouldStartExpireTimerWithTransaction:(SDSAnyReadTransaction *)transaction
|
||||
{
|
||||
for (NSString *attachmentId in self.attachmentIds) {
|
||||
TSAttachment *_Nullable attachment =
|
||||
[TSAttachment anyFetchWithUniqueId:attachmentId transaction:transaction.asAnyRead];
|
||||
TSAttachment *_Nullable attachment = [TSAttachment anyFetchWithUniqueId:attachmentId transaction:transaction];
|
||||
if ([attachment isKindOfClass:[TSAttachmentPointer class]]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
@ -7,7 +7,6 @@
|
||||
#import "SSKEnvironment.h"
|
||||
#import <SignalCoreKit/NSDate+OWS.h>
|
||||
#import <SignalServiceKit/SignalServiceKit-Swift.h>
|
||||
#import <YapDatabase/YapDatabaseConnection.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
|
||||
@ -110,7 +110,7 @@ NS_SWIFT_NAME(init(uniqueId:receivedAtTimestamp:sortId:timestamp:uniqueThreadId:
|
||||
- (nullable NSString *)oversizeTextWithTransaction:(SDSAnyReadTransaction *)transaction;
|
||||
- (nullable NSString *)bodyTextWithTransaction:(SDSAnyReadTransaction *)transaction;
|
||||
|
||||
- (BOOL)shouldStartExpireTimerWithTransaction:(YapDatabaseReadTransaction *)transaction;
|
||||
- (BOOL)shouldStartExpireTimerWithTransaction:(SDSAnyReadTransaction *)transaction;
|
||||
|
||||
- (BOOL)hasRenderableContent;
|
||||
|
||||
|
||||
@ -14,8 +14,6 @@
|
||||
#import <SignalCoreKit/NSDate+OWS.h>
|
||||
#import <SignalCoreKit/NSString+OWS.h>
|
||||
#import <SignalServiceKit/SignalServiceKit-Swift.h>
|
||||
#import <YapDatabase/YapDatabase.h>
|
||||
#import <YapDatabase/YapDatabaseTransaction.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@ -240,7 +238,7 @@ perMessageExpirationDurationSeconds:(unsigned int)perMessageExpirationDurationSe
|
||||
[self updateExpiresAt];
|
||||
}
|
||||
|
||||
- (BOOL)shouldStartExpireTimerWithTransaction:(YapDatabaseReadTransaction *)transaction
|
||||
- (BOOL)shouldStartExpireTimerWithTransaction:(SDSAnyReadTransaction *)transaction
|
||||
{
|
||||
return self.hasPerConversationExpiration;
|
||||
}
|
||||
@ -467,16 +465,13 @@ perMessageExpirationDurationSeconds:(unsigned int)perMessageExpirationDurationSe
|
||||
return NSLocalizedString(
|
||||
@"STICKER_MESSAGE_PREVIEW", @"Preview text shown in notifications and home view for sticker messages.");
|
||||
} else {
|
||||
if (transaction.transitional_yapReadTransaction) {
|
||||
// some cases aren't yet handled by GRDB
|
||||
OWSFailDebug(@"message has neither body nor attachment.");
|
||||
}
|
||||
OWSFailDebug(@"message has no renderable content.");
|
||||
// TODO: We should do better here.
|
||||
return @"";
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Convert to Any.
|
||||
// GRDB TODO: Convert to Any.
|
||||
- (void)saveWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
// StickerManager does reference counting of "known" sticker packs.
|
||||
@ -492,7 +487,7 @@ perMessageExpirationDurationSeconds:(unsigned int)perMessageExpirationDurationSe
|
||||
[super saveWithTransaction:transaction];
|
||||
}
|
||||
|
||||
// TODO: Convert to Any.
|
||||
// GRDB TODO: Convert to Any.
|
||||
- (void)removeWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
// StickerManager does reference counting of "known" sticker packs.
|
||||
|
||||
@ -627,7 +627,7 @@ perMessageExpirationDurationSeconds:perMessageExpirationDurationSeconds
|
||||
_storedMessageState = self.messageState;
|
||||
}
|
||||
|
||||
- (BOOL)shouldStartExpireTimerWithTransaction:(YapDatabaseReadTransaction *)transaction
|
||||
- (BOOL)shouldStartExpireTimerWithTransaction:(SDSAnyReadTransaction *)transaction
|
||||
{
|
||||
// It's not clear if we should wait until _all_ recipients have reached "sent or later"
|
||||
// (which could never occur if one group member is unregistered) or only wait until
|
||||
|
||||
@ -50,7 +50,7 @@ NS_SWIFT_NAME(init(uniqueId:receivedAtTimestamp:sortId:timestamp:uniqueThreadId:
|
||||
|
||||
#ifdef DEBUG
|
||||
+ (nullable instancetype)untrustedKeyWithEnvelope:(SSKProtoEnvelope *)envelope
|
||||
withTransaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
withTransaction:(SDSAnyWriteTransaction *)transaction;
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
@ -37,10 +37,10 @@ __attribute__((deprecated)) @interface TSInvalidIdentityKeyReceivingErrorMessage
|
||||
// We no longer create these messages, but they might exist on legacy clients so it's useful to be able to
|
||||
// create them with the debug UI
|
||||
+ (nullable instancetype)untrustedKeyWithEnvelope:(SSKProtoEnvelope *)envelope
|
||||
withTransaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
withTransaction:(SDSAnyWriteTransaction *)transaction
|
||||
{
|
||||
TSContactThread *contactThread = [TSContactThread getOrCreateThreadWithContactAddress:envelope.sourceAddress
|
||||
transaction:transaction.asAnyWrite];
|
||||
TSContactThread *contactThread =
|
||||
[TSContactThread getOrCreateThreadWithContactAddress:envelope.sourceAddress transaction:transaction];
|
||||
|
||||
// Legit usage of senderTimestamp, references message which failed to decrypt
|
||||
TSInvalidIdentityKeyReceivingErrorMessage *errorMessage =
|
||||
|
||||
@ -74,17 +74,14 @@ static NSString *const OWSDisappearingMessageFinderExpiresAtIndex = @"index_mess
|
||||
OWSAssertDebug([object isKindOfClass:[TSOutgoingMessage class]] || [object isKindOfClass:[TSIncomingMessage class]]);
|
||||
|
||||
TSMessage *message = (TSMessage *)object;
|
||||
if (transaction.transitional_yapReadTransaction) {
|
||||
if ([message shouldStartExpireTimerWithTransaction:
|
||||
transaction.transitional_yapReadTransaction]) {
|
||||
if ([message isKindOfClass:[TSIncomingMessage class]]) {
|
||||
TSIncomingMessage *incomingMessage = (TSIncomingMessage *)message;
|
||||
if (!incomingMessage.wasRead) {
|
||||
return;
|
||||
}
|
||||
if ([message shouldStartExpireTimerWithTransaction:transaction]) {
|
||||
if ([message isKindOfClass:[TSIncomingMessage class]]) {
|
||||
TSIncomingMessage *incomingMessage = (TSIncomingMessage *)message;
|
||||
if (!incomingMessage.wasRead) {
|
||||
return;
|
||||
}
|
||||
[messageIds addObject:key];
|
||||
}
|
||||
[messageIds addObject:key];
|
||||
}
|
||||
}];
|
||||
|
||||
@ -178,11 +175,9 @@ static NSString *const OWSDisappearingMessageFinderExpiresAtIndex = @"index_mess
|
||||
continue;
|
||||
}
|
||||
|
||||
if (transaction.transitional_yapReadTransaction) {
|
||||
if (![message shouldStartExpireTimerWithTransaction:transaction.transitional_yapReadTransaction]) {
|
||||
OWSFailDebug(@"object: %@ shouldn't expire.", message);
|
||||
continue;
|
||||
}
|
||||
if (![message shouldStartExpireTimerWithTransaction:transaction]) {
|
||||
OWSFailDebug(@"object: %@ shouldn't expire.", message);
|
||||
continue;
|
||||
}
|
||||
|
||||
block(message);
|
||||
@ -262,7 +257,7 @@ static NSString *const OWSDisappearingMessageFinderExpiresAtIndex = @"index_mess
|
||||
}
|
||||
TSMessage *message = (TSMessage *)object;
|
||||
|
||||
if (![message shouldStartExpireTimerWithTransaction:transaction]) {
|
||||
if (![message shouldStartExpireTimerWithTransaction:transaction.asAnyRead]) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -610,32 +610,21 @@ NSError *EnsureDecryptError(NSError *_Nullable error, NSString *fallbackErrorDes
|
||||
return;
|
||||
}
|
||||
|
||||
if (!transaction.transitional_yapWriteTransaction) {
|
||||
OWSFailDebug(@"GRDB TODO");
|
||||
return;
|
||||
}
|
||||
|
||||
if ([exception.name isEqualToString:NoSessionException]) {
|
||||
OWSProdErrorWEnvelope([OWSAnalyticsEvents messageManagerErrorNoSession], envelope);
|
||||
errorMessage = [TSErrorMessage missingSessionWithEnvelope:envelope
|
||||
withTransaction:transaction.transitional_yapWriteTransaction];
|
||||
errorMessage = [TSErrorMessage missingSessionWithEnvelope:envelope withTransaction:transaction];
|
||||
} else if ([exception.name isEqualToString:InvalidKeyException]) {
|
||||
OWSProdErrorWEnvelope([OWSAnalyticsEvents messageManagerErrorInvalidKey], envelope);
|
||||
errorMessage =
|
||||
[TSErrorMessage invalidKeyExceptionWithEnvelope:envelope
|
||||
withTransaction:transaction.transitional_yapWriteTransaction];
|
||||
errorMessage = [TSErrorMessage invalidKeyExceptionWithEnvelope:envelope withTransaction:transaction];
|
||||
} else if ([exception.name isEqualToString:InvalidKeyIdException]) {
|
||||
OWSProdErrorWEnvelope([OWSAnalyticsEvents messageManagerErrorInvalidKeyId], envelope);
|
||||
errorMessage =
|
||||
[TSErrorMessage invalidKeyExceptionWithEnvelope:envelope
|
||||
withTransaction:transaction.transitional_yapWriteTransaction];
|
||||
errorMessage = [TSErrorMessage invalidKeyExceptionWithEnvelope:envelope withTransaction:transaction];
|
||||
} else if ([exception.name isEqualToString:DuplicateMessageException]) {
|
||||
// Duplicate messages are silently discarded.
|
||||
return;
|
||||
} else if ([exception.name isEqualToString:InvalidVersionException]) {
|
||||
OWSProdErrorWEnvelope([OWSAnalyticsEvents messageManagerErrorInvalidMessageVersion], envelope);
|
||||
errorMessage = [TSErrorMessage invalidVersionWithEnvelope:envelope
|
||||
withTransaction:transaction.transitional_yapWriteTransaction];
|
||||
errorMessage = [TSErrorMessage invalidVersionWithEnvelope:envelope withTransaction:transaction];
|
||||
} else if ([exception.name isEqualToString:UntrustedIdentityKeyException]) {
|
||||
// Should no longer get here, since we now record the new identity for incoming messages.
|
||||
OWSProdErrorWEnvelope([OWSAnalyticsEvents messageManagerErrorUntrustedIdentityKeyException], envelope);
|
||||
@ -643,8 +632,7 @@ NSError *EnsureDecryptError(NSError *_Nullable error, NSString *fallbackErrorDes
|
||||
return;
|
||||
} else {
|
||||
OWSProdErrorWEnvelope([OWSAnalyticsEvents messageManagerErrorCorruptMessage], envelope);
|
||||
errorMessage = [TSErrorMessage corruptedMessageWithEnvelope:envelope
|
||||
withTransaction:transaction.transitional_yapWriteTransaction];
|
||||
errorMessage = [TSErrorMessage corruptedMessageWithEnvelope:envelope withTransaction:transaction];
|
||||
}
|
||||
|
||||
OWSAssertDebug(errorMessage);
|
||||
|
||||
@ -6,7 +6,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class TSMessage;
|
||||
@class TSThread;
|
||||
@class YapDatabaseReadTransaction;
|
||||
|
||||
@interface OWSMessageUtils : NSObject
|
||||
|
||||
|
||||
@ -44,7 +44,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
quotedMessage:nil
|
||||
contactShare:nil
|
||||
linkPreview:nil];
|
||||
[self yapWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self readWithBlock:^(SDSAnyReadTransaction *transaction) {
|
||||
XCTAssertFalse([message shouldStartExpireTimerWithTransaction:transaction]);
|
||||
}];
|
||||
}
|
||||
@ -63,7 +63,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
quotedMessage:nil
|
||||
contactShare:nil
|
||||
linkPreview:nil];
|
||||
[self yapWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self writeWithBlock:^(SDSAnyWriteTransaction *transaction) {
|
||||
[message updateWithSentRecipient:self.contactId wasSentByUD:NO transaction:transaction];
|
||||
XCTAssertTrue([message shouldStartExpireTimerWithTransaction:transaction]);
|
||||
}];
|
||||
@ -83,7 +83,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
quotedMessage:nil
|
||||
contactShare:nil
|
||||
linkPreview:nil];
|
||||
[self yapWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self readWithBlock:^(SDSAnyReadTransaction *transaction) {
|
||||
XCTAssertFalse([message shouldStartExpireTimerWithTransaction:transaction]);
|
||||
}];
|
||||
}
|
||||
@ -102,7 +102,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
quotedMessage:nil
|
||||
contactShare:nil
|
||||
linkPreview:nil];
|
||||
[self yapWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self writeWithBlock:^(SDSAnyWriteTransaction *transaction) {
|
||||
[message updateWithMarkingAllUnsentRecipientsAsSendingWithTransaction:transaction];
|
||||
XCTAssertFalse([message shouldStartExpireTimerWithTransaction:transaction]);
|
||||
}];
|
||||
|
||||
Loading…
Reference in New Issue
Block a user