diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 41d3a0678..90dbb4f2f 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -367,6 +367,7 @@ B684A46D19C3446200B11029 /* PushManagerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = B684A46C19C3446200B11029 /* PushManagerTest.m */; }; B6850E5A1995A4710068E715 /* whisperFake.cer in Resources */ = {isa = PBXBuildFile; fileRef = B6850E591995A4710068E715 /* whisperFake.cer */; }; B68B0E8A1A54284100DE8A02 /* TSInvalidIdentityKeyErrorMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = B68B0E891A54284100DE8A02 /* TSInvalidIdentityKeyErrorMessage.m */; }; + B692BF071A76EF0F002786DA /* TSDatabaseSecondaryIndexes.m in Sources */ = {isa = PBXBuildFile; fileRef = B692BF061A76EF0F002786DA /* TSDatabaseSecondaryIndexes.m */; }; B69CD25119773E79005CE69A /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B69CD25019773E79005CE69A /* XCTest.framework */; }; B6A3EB4B1A423B3800B2236B /* TSAttachmentAdapter.m in Sources */ = {isa = PBXBuildFile; fileRef = B6A3EB4A1A423B3800B2236B /* TSAttachmentAdapter.m */; }; B6AE33BD1A1EB121003DF39D /* TSGroupModel.m in Sources */ = {isa = PBXBuildFile; fileRef = B6AE33BC1A1EB121003DF39D /* TSGroupModel.m */; }; @@ -1007,6 +1008,8 @@ B68B0E881A54284100DE8A02 /* TSInvalidIdentityKeyErrorMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSInvalidIdentityKeyErrorMessage.h; sourceTree = ""; }; B68B0E891A54284100DE8A02 /* TSInvalidIdentityKeyErrorMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSInvalidIdentityKeyErrorMessage.m; sourceTree = ""; }; B68B0E8D1A542AD700DE8A02 /* TSErrorMessage_privateConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSErrorMessage_privateConstructor.h; sourceTree = ""; }; + B692BF051A76EF0F002786DA /* TSDatabaseSecondaryIndexes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSDatabaseSecondaryIndexes.h; sourceTree = ""; }; + B692BF061A76EF0F002786DA /* TSDatabaseSecondaryIndexes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSDatabaseSecondaryIndexes.m; sourceTree = ""; }; B69CD25019773E79005CE69A /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; B6A3EB491A423B3800B2236B /* TSAttachmentAdapter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSAttachmentAdapter.h; sourceTree = ""; }; B6A3EB4A1A423B3800B2236B /* TSAttachmentAdapter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSAttachmentAdapter.m; sourceTree = ""; }; @@ -2422,6 +2425,8 @@ B6B0963F1A1D25ED008BFAA6 /* AxolotlStore */, B6B0964A1A1D25ED008BFAA6 /* TSDatabaseView.h */, B6B0964B1A1D25ED008BFAA6 /* TSDatabaseView.m */, + B692BF051A76EF0F002786DA /* TSDatabaseSecondaryIndexes.h */, + B692BF061A76EF0F002786DA /* TSDatabaseSecondaryIndexes.m */, B6B0964C1A1D25ED008BFAA6 /* TSStorageKeys.h */, B6B0964D1A1D25ED008BFAA6 /* TSStorageManager+keyingMaterial.h */, B6B0964E1A1D25ED008BFAA6 /* TSStorageManager+keyingMaterial.m */, @@ -3202,6 +3207,7 @@ B6B096681A1D25ED008BFAA6 /* TSRecipient.m in Sources */, 76EB05FE18170B33006006FC /* InitiateSignal.pb.m in Sources */, 76EB05CA18170B33006006FC /* RecipientUnavailable.m in Sources */, + B692BF071A76EF0F002786DA /* TSDatabaseSecondaryIndexes.m in Sources */, B6B0968D1A1D25ED008BFAA6 /* TSStorageManager+keyingMaterial.m in Sources */, E197B61418BBEC1A00F073E5 /* DropoutTracker.m in Sources */, 76EB062C18170B33006006FC /* OperationFailed.m in Sources */, diff --git a/Signal/src/textsecure/Messages/TSInteraction.h b/Signal/src/textsecure/Messages/TSInteraction.h index 85e3d62fd..3b44fa366 100644 --- a/Signal/src/textsecure/Messages/TSInteraction.h +++ b/Signal/src/textsecure/Messages/TSInteraction.h @@ -37,4 +37,7 @@ extern const struct TSMessageEdges { + (NSString*)stringFromTimeStamp:(uint64_t)timestamp; + (uint64_t)timeStampFromString:(NSString*)string; ++ (instancetype)interactionForTimestamp:(uint64_t)timestamp withTransaction:(YapDatabaseReadWriteTransaction*)transaction; + + @end diff --git a/Signal/src/textsecure/Messages/TSInteraction.m b/Signal/src/textsecure/Messages/TSInteraction.m index c95fab129..54636486f 100644 --- a/Signal/src/textsecure/Messages/TSInteraction.m +++ b/Signal/src/textsecure/Messages/TSInteraction.m @@ -7,8 +7,11 @@ // #import "TSInteraction.h" + +#import "TSDatabaseSecondaryIndexes.h" #import "TSStorageManager+messageIDs.h" + const struct TSMessageRelationships TSMessageRelationships = { .threadUniqueId = @"threadUniqueId", }; @@ -30,6 +33,25 @@ const struct TSMessageEdges TSMessageEdges = { return self; } ++ (instancetype)interactionForTimestamp:(uint64_t)timestamp withTransaction:(YapDatabaseReadWriteTransaction *)transaction{ + __block int counter = 0; + __block TSInteraction *interaction; + + [TSDatabaseSecondaryIndexes enumerateMessagesWithTimestamp:timestamp withBlock:^(NSString *collection, NSString *key, BOOL *stop) { + + if (counter != 0) { + DDLogWarn(@"The database contains two colliding timestamps at: %lld.", timestamp); + return; + } + + interaction = [TSInteraction fetchObjectWithUniqueID:key transaction:transaction]; + + counter ++; + } usingTransaction:transaction]; + + return interaction; +} + #pragma mark YapDatabaseRelationshipNode @@ -84,7 +106,8 @@ const struct TSMessageEdges TSMessageEdges = { [super saveWithTransaction:transaction]; - TSThread *fetchedThread = [TSThread fetchObjectWithUniqueID:self.uniqueThreadId transaction:transaction]; + TSThread *fetchedThread = [TSThread fetchObjectWithUniqueID:self.uniqueThreadId + transaction:transaction]; if (!fetchedThread.latestMessageId || [self.date timeIntervalSinceDate:fetchedThread.lastMessageDate] > 0) { fetchedThread.latestMessageId = self.uniqueId; diff --git a/Signal/src/textsecure/Messages/TSMessagesManager.m b/Signal/src/textsecure/Messages/TSMessagesManager.m index 810876efa..e8e6dab0e 100644 --- a/Signal/src/textsecure/Messages/TSMessagesManager.m +++ b/Signal/src/textsecure/Messages/TSMessagesManager.m @@ -41,6 +41,7 @@ #import "ContactsManager.h" #import +#import #define ddLogLevel LOG_LEVEL_VERBOSE @@ -102,10 +103,12 @@ - (void)handleDeliveryReceipt:(IncomingPushMessageSignal*)signal{ [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - TSOutgoingMessage *message = [TSOutgoingMessage fetchObjectWithUniqueID:[TSInteraction stringFromTimeStamp:signal.timestamp] transaction:transaction]; - if(![message isKindOfClass:[TSInfoMessage class]]){ - message.messageState = TSOutgoingMessageStateDelivered; - [message saveWithTransaction:transaction]; + TSInteraction *interaction = [TSInteraction interactionForTimestamp:signal.timestamp withTransaction:transaction]; + if ([interaction isKindOfClass:[TSOutgoingMessage class]]) { + TSOutgoingMessage *outgoingMessage = (TSOutgoingMessage*)interaction; + outgoingMessage.messageState = TSOutgoingMessageStateDelivered; + + [outgoingMessage saveWithTransaction:transaction]; } }]; } @@ -118,7 +121,8 @@ if (![storageManager containsSession:recipientId deviceId:deviceId]) { [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - TSErrorMessage *errorMessage = [TSErrorMessage missingSessionWithSignal:secureMessage withTransaction:transaction]; + TSErrorMessage *errorMessage = [TSErrorMessage missingSessionWithSignal:secureMessage + withTransaction:transaction]; [errorMessage saveWithTransaction:transaction]; }]; return; @@ -293,11 +297,16 @@ thread = gThread; } else{ - TSContactThread *cThread = [TSContactThread getOrCreateThreadWithContactId:message.source transaction:transaction]; + TSContactThread *cThread = [TSContactThread getOrCreateThreadWithContactId:message.source + transaction:transaction]; [cThread saveWithTransaction:transaction]; - incomingMessage = [[TSIncomingMessage alloc] initWithTimestamp:timeStamp inThread:cThread messageBody:body attachments:attachments]; + incomingMessage = [[TSIncomingMessage alloc] initWithTimestamp:timeStamp + inThread:cThread + messageBody:body + attachments:attachments]; [incomingMessage saveWithTransaction:transaction]; thread = cThread; + if (completionBlock) { completionBlock(incomingMessage.uniqueId); } diff --git a/Signal/src/textsecure/Storage/TSDatabaseSecondaryIndexes.h b/Signal/src/textsecure/Storage/TSDatabaseSecondaryIndexes.h new file mode 100644 index 000000000..25c7ec05c --- /dev/null +++ b/Signal/src/textsecure/Storage/TSDatabaseSecondaryIndexes.h @@ -0,0 +1,20 @@ +// +// TSDatabaseSecondaryIndexes.h +// Signal +// +// Created by Frederic Jacobs on 26/01/15. +// Copyright (c) 2015 Open Whisper Systems. All rights reserved. +// + +#import + +#import +#import + +@interface TSDatabaseSecondaryIndexes : NSObject + ++ (YapDatabaseSecondaryIndex*)registerTimeStampIndex; + ++ (void)enumerateMessagesWithTimestamp:(uint64_t)timestamp withBlock:(void (^)(NSString *collection, NSString *key, BOOL *stop))block usingTransaction:(YapDatabaseReadWriteTransaction*)transaction; + +@end diff --git a/Signal/src/textsecure/Storage/TSDatabaseSecondaryIndexes.m b/Signal/src/textsecure/Storage/TSDatabaseSecondaryIndexes.m new file mode 100644 index 000000000..2e7dd597f --- /dev/null +++ b/Signal/src/textsecure/Storage/TSDatabaseSecondaryIndexes.m @@ -0,0 +1,49 @@ +// +// TSDatabaseSecondaryIndexes.m +// Signal +// +// Created by Frederic Jacobs on 26/01/15. +// Copyright (c) 2015 Open Whisper Systems. All rights reserved. +// + +#import "TSDatabaseSecondaryIndexes.h" + +#import + +#import "TSInteraction.h" + +#define TSTimeStampSQLiteIndex @"messagesTimeStamp" + +@implementation TSDatabaseSecondaryIndexes + ++ (YapDatabaseSecondaryIndex*)registerTimeStampIndex { + YapDatabaseSecondaryIndexSetup *setup = [ [YapDatabaseSecondaryIndexSetup alloc] init]; + [setup addColumn:TSTimeStampSQLiteIndex withType:YapDatabaseSecondaryIndexTypeReal]; + + YapDatabaseSecondaryIndexWithObjectBlock block = ^(NSMutableDictionary *dict, NSString *collection, NSString *key, id object){ + + if ([object isKindOfClass:[TSInteraction class]]) + { + TSInteraction *interaction = (TSInteraction *)object; + + [dict setObject:@(interaction.timestamp) forKey:TSTimeStampSQLiteIndex]; + } + }; + + YapDatabaseSecondaryIndexHandler *handler = [YapDatabaseSecondaryIndexHandler withObjectBlock:block]; + + YapDatabaseSecondaryIndex *secondaryIndex = [[YapDatabaseSecondaryIndex alloc] initWithSetup:setup handler:handler]; + + return secondaryIndex; +} + + ++ (void)enumerateMessagesWithTimestamp:(uint64_t)timestamp + withBlock:(void (^)(NSString *collection, NSString *key, BOOL *stop))block + usingTransaction:(YapDatabaseReadWriteTransaction *)transaction { + + NSString *formattedString = [NSString stringWithFormat:@"WHERE %@ = %lld", TSTimeStampSQLiteIndex,timestamp]; + YapDatabaseQuery *query = [YapDatabaseQuery queryWithFormat:formattedString]; + [[transaction ext:@"idx"] enumerateKeysMatchingQuery:query usingBlock:block]; +} +@end diff --git a/Signal/src/textsecure/Storage/TSStorageManager.m b/Signal/src/textsecure/Storage/TSStorageManager.m index aac6b6fe2..8de34be57 100644 --- a/Signal/src/textsecure/Storage/TSStorageManager.m +++ b/Signal/src/textsecure/Storage/TSStorageManager.m @@ -21,6 +21,7 @@ #import #import "TSDatabaseView.h" +#import "TSDatabaseSecondaryIndexes.h" NSString *const TSUIDatabaseConnectionDidUpdateNotification = @"TSUIDatabaseConnectionDidUpdateNotification"; @@ -73,6 +74,8 @@ static NSString * keychainDBPassAccount = @"TSDatabasePass"; [TSDatabaseView registerBuddyConversationDatabaseView]; [TSDatabaseView registerUnreadDatabaseView]; + [self.database registerExtension:[TSDatabaseSecondaryIndexes registerTimeStampIndex] withName:@"idx"]; + [self.database registerExtension:[[YapDatabaseRelationship alloc] init] withName:@"TSRelationships"]; }