session-ios/SignalServiceKit/src/Storage/OWSIncomingMessageFinder.m
Michael Kirk ccb4a88742 Import SSK (and history) into Signal-iOS
git remote add ssk ../SignalServiceKit
git remote update
git merge -s ours --allow-unrelated-histories --no-commit ssk/master
git read-tree --prefix=SignalServiceKit -u ssk/master
git commit
2017-07-21 13:55:01 -04:00

162 lines
5.4 KiB
Objective-C

//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import "OWSIncomingMessageFinder.h"
#import "TSIncomingMessage.h"
#import "TSStorageManager.h"
#import <YapDatabase/YapDatabase.h>
#import <YapDatabase/YapDatabaseSecondaryIndex.h>
NS_ASSUME_NONNULL_BEGIN
NSString *const OWSIncomingMessageFinderExtensionName = @"OWSIncomingMessageFinderExtensionName";
NSString *const OWSIncomingMessageFinderColumnTimestamp = @"OWSIncomingMessageFinderColumnTimestamp";
NSString *const OWSIncomingMessageFinderColumnSourceId = @"OWSIncomingMessageFinderColumnSourceId";
NSString *const OWSIncomingMessageFinderColumnSourceDeviceId = @"OWSIncomingMessageFinderColumnSourceDeviceId";
@interface OWSIncomingMessageFinder ()
@property (nonatomic, readonly) YapDatabase *database;
@property (nonatomic, readonly) YapDatabaseConnection *dbConnection;
@end
@implementation OWSIncomingMessageFinder
@synthesize dbConnection = _dbConnection;
#pragma mark - init
- (instancetype)init
{
OWSAssert([TSStorageManager sharedManager].database != nil);
return [self initWithDatabase:[TSStorageManager sharedManager].database];
}
- (instancetype)initWithDatabase:(YapDatabase *)database
{
self = [super init];
if (!self) {
return self;
}
_database = database;
return self;
}
#pragma mark - properties
- (YapDatabaseConnection *)dbConnection
{
@synchronized (self) {
if (!_dbConnection) {
_dbConnection = self.database.newConnection;
}
}
return _dbConnection;
}
#pragma mark - YAP integration
- (YapDatabaseSecondaryIndex *)indexExtension
{
YapDatabaseSecondaryIndexSetup *setup = [YapDatabaseSecondaryIndexSetup new];
[setup addColumn:OWSIncomingMessageFinderColumnTimestamp withType:YapDatabaseSecondaryIndexTypeInteger];
[setup addColumn:OWSIncomingMessageFinderColumnSourceId withType:YapDatabaseSecondaryIndexTypeText];
[setup addColumn:OWSIncomingMessageFinderColumnSourceDeviceId withType:YapDatabaseSecondaryIndexTypeInteger];
YapDatabaseSecondaryIndexWithObjectBlock block = ^(YapDatabaseReadTransaction *transaction,
NSMutableDictionary *dict,
NSString *collection,
NSString *key,
id object) {
if ([object isKindOfClass:[TSIncomingMessage class]]) {
TSIncomingMessage *incomingMessage = (TSIncomingMessage *)object;
// On new messages authorId should be set on all incoming messages, but there was a time when authorId was
// only set on incoming group messages.
NSObject *authorIdOrNull = incomingMessage.authorId ? incomingMessage.authorId : [NSNull null];
[dict setObject:@(incomingMessage.timestamp) forKey:OWSIncomingMessageFinderColumnTimestamp];
[dict setObject:authorIdOrNull forKey:OWSIncomingMessageFinderColumnSourceId];
[dict setObject:@(incomingMessage.sourceDeviceId) forKey:OWSIncomingMessageFinderColumnSourceDeviceId];
}
};
YapDatabaseSecondaryIndexHandler *handler = [YapDatabaseSecondaryIndexHandler withObjectBlock:block];
return [[YapDatabaseSecondaryIndex alloc] initWithSetup:setup handler:handler];
}
- (void)asyncRegisterExtension
{
DDLogInfo(@"%@ registering async.", self.tag);
[self.database asyncRegisterExtension:self.indexExtension
withName:OWSIncomingMessageFinderExtensionName
completionBlock:^(BOOL ready) {
DDLogInfo(@"%@ finished registering async.", self.tag);
}];
}
// We should not normally hit this, as we should have prefer registering async, but it is useful for testing.
- (void)registerExtension
{
DDLogError(@"%@ registering SYNC. We should prefer async when possible.", self.tag);
[self.database registerExtension:self.indexExtension withName:OWSIncomingMessageFinderExtensionName];
}
#pragma mark - instance methods
- (BOOL)existsMessageWithTimestamp:(uint64_t)timestamp
sourceId:(NSString *)sourceId
sourceDeviceId:(uint32_t)sourceDeviceId
{
if (![self.database registeredExtension:OWSIncomingMessageFinderExtensionName]) {
DDLogError(@"%@ in %s but extension is not registered", self.tag, __PRETTY_FUNCTION__);
OWSAssert(NO);
// we should be initializing this at startup rather than have an unexpectedly slow lazy setup at random.
[self registerExtension];
}
NSString *queryFormat = [NSString stringWithFormat:@"WHERE %@ = ? AND %@ = ? AND %@ = ?",
OWSIncomingMessageFinderColumnTimestamp,
OWSIncomingMessageFinderColumnSourceId,
OWSIncomingMessageFinderColumnSourceDeviceId];
// YapDatabaseQuery params must be objects
YapDatabaseQuery *query = [YapDatabaseQuery queryWithFormat:queryFormat, @(timestamp), sourceId, @(sourceDeviceId)];
__block NSUInteger count;
__block BOOL success;
[self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
success = [[transaction ext:OWSIncomingMessageFinderExtensionName] getNumberOfRows:&count matchingQuery:query];
}];
if (!success) {
OWSAssert(NO);
return NO;
}
return count > 0;
}
#pragma mark - Logging
+ (NSString *)tag
{
return [NSString stringWithFormat:@"[%@]", self.class];
}
- (NSString *)tag
{
return self.class.tag;
}
@end
NS_ASSUME_NONNULL_END