|
|
@ -4,7 +4,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
#import "TSStorageManager+SessionStore.h"
|
|
|
|
#import "TSStorageManager+SessionStore.h"
|
|
|
|
|
|
|
|
|
|
|
|
#define TSStorageManagerSessionStoreCollection @"TSStorageManagerSessionStoreCollection"
|
|
|
|
NSString *const TSStorageManagerSessionStoreCollection = @"TSStorageManagerSessionStoreCollection";
|
|
|
|
|
|
|
|
NSString *const kSessionStoreDBConnectionKey = @"kSessionStoreDBConnectionKey";
|
|
|
|
|
|
|
|
|
|
|
|
void AssertIsOnSessionStoreQueue()
|
|
|
|
void AssertIsOnSessionStoreQueue()
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -17,19 +18,46 @@ void AssertIsOnSessionStoreQueue()
|
|
|
|
|
|
|
|
|
|
|
|
@implementation TSStorageManager (SessionStore)
|
|
|
|
@implementation TSStorageManager (SessionStore)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Special purpose dbConnection which disables the object cache to better enforce transaction semantics on the store.
|
|
|
|
|
|
|
|
* Note that it's still technically possible to access this collection from a different collection,
|
|
|
|
|
|
|
|
* but that should be considered a bug.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
+ (YapDatabaseConnection *)sessionDBConnection
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
static dispatch_once_t onceToken;
|
|
|
|
|
|
|
|
static YapDatabaseConnection *sessionDBConnection;
|
|
|
|
|
|
|
|
dispatch_once(&onceToken, ^{
|
|
|
|
|
|
|
|
sessionDBConnection = [TSStorageManager sharedManager].newDatabaseConnection;
|
|
|
|
|
|
|
|
sessionDBConnection.objectCacheEnabled = NO;
|
|
|
|
|
|
|
|
#if DEBUG
|
|
|
|
|
|
|
|
sessionDBConnection.permittedTransactions = YDB_AnySyncTransaction;
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return sessionDBConnection;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- (YapDatabaseConnection *)sessionDBConnection
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return [[self class] sessionDBConnection];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#pragma mark - SessionStore
|
|
|
|
#pragma mark - SessionStore
|
|
|
|
|
|
|
|
|
|
|
|
- (SessionRecord *)loadSession:(NSString *)contactIdentifier deviceId:(int)deviceId
|
|
|
|
- (SessionRecord *)loadSession:(NSString *)contactIdentifier deviceId:(int)deviceId
|
|
|
|
{
|
|
|
|
{
|
|
|
|
AssertIsOnSessionStoreQueue();
|
|
|
|
AssertIsOnSessionStoreQueue();
|
|
|
|
|
|
|
|
|
|
|
|
NSDictionary *dictionary =
|
|
|
|
__block NSDictionary *dictionary;
|
|
|
|
[self dictionaryForKey:contactIdentifier inCollection:TSStorageManagerSessionStoreCollection];
|
|
|
|
[self.sessionDBConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
|
|
|
|
dictionary = [transaction objectForKey:contactIdentifier inCollection:TSStorageManagerSessionStoreCollection];
|
|
|
|
|
|
|
|
}];
|
|
|
|
|
|
|
|
|
|
|
|
SessionRecord *record;
|
|
|
|
SessionRecord *record;
|
|
|
|
|
|
|
|
|
|
|
|
if (dictionary) {
|
|
|
|
if (dictionary) {
|
|
|
|
record = [dictionary objectForKey:[self keyForInt:deviceId]];
|
|
|
|
record = [dictionary objectForKey:@(deviceId)];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!record) {
|
|
|
|
if (!record) {
|
|
|
@ -46,20 +74,12 @@ void AssertIsOnSessionStoreQueue()
|
|
|
|
OWSAssert(NO);
|
|
|
|
OWSAssert(NO);
|
|
|
|
AssertIsOnSessionStoreQueue();
|
|
|
|
AssertIsOnSessionStoreQueue();
|
|
|
|
|
|
|
|
|
|
|
|
NSDictionary *dictionary =
|
|
|
|
__block NSDictionary *dictionary;
|
|
|
|
[self objectForKey:contactIdentifier inCollection:TSStorageManagerSessionStoreCollection];
|
|
|
|
[self.sessionDBConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
|
|
|
|
dictionary = [transaction objectForKey:contactIdentifier inCollection:TSStorageManagerSessionStoreCollection];
|
|
|
|
NSMutableArray *subDevicesSessions = [NSMutableArray array];
|
|
|
|
}];
|
|
|
|
|
|
|
|
|
|
|
|
if (dictionary) {
|
|
|
|
|
|
|
|
for (NSString *key in [dictionary allKeys]) {
|
|
|
|
|
|
|
|
NSNumber *number = @([key doubleValue]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[subDevicesSessions addObject:number];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return subDevicesSessions;
|
|
|
|
return dictionary ? dictionary.allKeys : @[];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (void)storeSession:(NSString *)contactIdentifier deviceId:(int)deviceId session:(SessionRecord *)session
|
|
|
|
- (void)storeSession:(NSString *)contactIdentifier deviceId:(int)deviceId session:(SessionRecord *)session
|
|
|
@ -71,18 +91,27 @@ void AssertIsOnSessionStoreQueue()
|
|
|
|
// YapDB (initWithCoder:). However, because YapDB has an object cache, rather than fetching/deserializing, it's
|
|
|
|
// YapDB (initWithCoder:). However, because YapDB has an object cache, rather than fetching/deserializing, it's
|
|
|
|
// possible we'd get back *this* exact instance of the object (which, at this point, is still potentially "fresh"),
|
|
|
|
// possible we'd get back *this* exact instance of the object (which, at this point, is still potentially "fresh"),
|
|
|
|
// thus we explicitly mark this instance as "unfresh", any time we save.
|
|
|
|
// thus we explicitly mark this instance as "unfresh", any time we save.
|
|
|
|
|
|
|
|
// NOTE: this may no longer be necessary now that we have a non-caching session db connection.
|
|
|
|
[session markAsUnFresh];
|
|
|
|
[session markAsUnFresh];
|
|
|
|
|
|
|
|
|
|
|
|
NSMutableDictionary *dictionary =
|
|
|
|
__block NSDictionary *immutableDictionary;
|
|
|
|
[[self dictionaryForKey:contactIdentifier inCollection:TSStorageManagerSessionStoreCollection] mutableCopy];
|
|
|
|
[self.sessionDBConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
|
|
|
|
immutableDictionary =
|
|
|
|
|
|
|
|
[transaction objectForKey:contactIdentifier inCollection:TSStorageManagerSessionStoreCollection];
|
|
|
|
|
|
|
|
}];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NSMutableDictionary *dictionary = [immutableDictionary mutableCopy];
|
|
|
|
|
|
|
|
|
|
|
|
if (!dictionary) {
|
|
|
|
if (!dictionary) {
|
|
|
|
dictionary = [NSMutableDictionary dictionary];
|
|
|
|
dictionary = [NSMutableDictionary dictionary];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[dictionary setObject:session forKey:[self keyForInt:deviceId]];
|
|
|
|
[dictionary setObject:session forKey:@(deviceId)];
|
|
|
|
|
|
|
|
|
|
|
|
[self setObject:dictionary forKey:contactIdentifier inCollection:TSStorageManagerSessionStoreCollection];
|
|
|
|
// TODO copy dictionary back to Immutable
|
|
|
|
|
|
|
|
[self.sessionDBConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
|
|
|
|
|
|
|
[transaction setObject:dictionary forKey:contactIdentifier inCollection:TSStorageManagerSessionStoreCollection];
|
|
|
|
|
|
|
|
}];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (BOOL)containsSession:(NSString *)contactIdentifier deviceId:(int)deviceId
|
|
|
|
- (BOOL)containsSession:(NSString *)contactIdentifier deviceId:(int)deviceId
|
|
|
@ -97,16 +126,24 @@ void AssertIsOnSessionStoreQueue()
|
|
|
|
AssertIsOnSessionStoreQueue();
|
|
|
|
AssertIsOnSessionStoreQueue();
|
|
|
|
DDLogInfo(
|
|
|
|
DDLogInfo(
|
|
|
|
@"[TSStorageManager (SessionStore)] deleting session for contact: %@ device: %d", contactIdentifier, deviceId);
|
|
|
|
@"[TSStorageManager (SessionStore)] deleting session for contact: %@ device: %d", contactIdentifier, deviceId);
|
|
|
|
NSMutableDictionary *dictionary =
|
|
|
|
|
|
|
|
[[self dictionaryForKey:contactIdentifier inCollection:TSStorageManagerSessionStoreCollection] mutableCopy];
|
|
|
|
__block NSDictionary *immutableDictionary;
|
|
|
|
|
|
|
|
[self.sessionDBConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
|
|
|
|
|
|
|
immutableDictionary =
|
|
|
|
|
|
|
|
[transaction objectForKey:contactIdentifier inCollection:TSStorageManagerSessionStoreCollection];
|
|
|
|
|
|
|
|
}];
|
|
|
|
|
|
|
|
NSMutableDictionary *dictionary = [immutableDictionary mutableCopy];
|
|
|
|
|
|
|
|
|
|
|
|
if (!dictionary) {
|
|
|
|
if (!dictionary) {
|
|
|
|
dictionary = [NSMutableDictionary dictionary];
|
|
|
|
dictionary = [NSMutableDictionary dictionary];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[dictionary removeObjectForKey:[self keyForInt:deviceId]];
|
|
|
|
[dictionary removeObjectForKey:@(deviceId)];
|
|
|
|
|
|
|
|
|
|
|
|
[self setObject:dictionary forKey:contactIdentifier inCollection:TSStorageManagerSessionStoreCollection];
|
|
|
|
// TODO copy dictionary back to Immutable
|
|
|
|
|
|
|
|
[self.sessionDBConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
|
|
|
|
|
|
|
[transaction setObject:dictionary forKey:contactIdentifier inCollection:TSStorageManagerSessionStoreCollection];
|
|
|
|
|
|
|
|
}];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- (void)deleteAllSessionsForContact:(NSString *)contactIdentifier
|
|
|
|
- (void)deleteAllSessionsForContact:(NSString *)contactIdentifier
|
|
|
@ -114,13 +151,9 @@ void AssertIsOnSessionStoreQueue()
|
|
|
|
AssertIsOnSessionStoreQueue();
|
|
|
|
AssertIsOnSessionStoreQueue();
|
|
|
|
DDLogInfo(@"[TSStorageManager (SessionStore)] deleting all sessions for contact:%@", contactIdentifier);
|
|
|
|
DDLogInfo(@"[TSStorageManager (SessionStore)] deleting all sessions for contact:%@", contactIdentifier);
|
|
|
|
|
|
|
|
|
|
|
|
[self removeObjectForKey:contactIdentifier inCollection:TSStorageManagerSessionStoreCollection];
|
|
|
|
[self.sessionDBConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
|
|
|
}
|
|
|
|
[transaction removeObjectForKey:contactIdentifier inCollection:TSStorageManagerSessionStoreCollection];
|
|
|
|
|
|
|
|
}];
|
|
|
|
#pragma mark - util
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- (NSNumber *)keyForInt:(int)number {
|
|
|
|
|
|
|
|
return [NSNumber numberWithInt:number];
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#pragma mark - debug
|
|
|
|
#pragma mark - debug
|
|
|
@ -130,7 +163,7 @@ void AssertIsOnSessionStoreQueue()
|
|
|
|
AssertIsOnSessionStoreQueue();
|
|
|
|
AssertIsOnSessionStoreQueue();
|
|
|
|
|
|
|
|
|
|
|
|
NSString *tag = @"[TSStorageManager (SessionStore)]";
|
|
|
|
NSString *tag = @"[TSStorageManager (SessionStore)]";
|
|
|
|
[self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
|
|
|
|
[self.sessionDBConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
|
|
|
|
DDLogDebug(@"%@ All Sessions:", tag);
|
|
|
|
DDLogDebug(@"%@ All Sessions:", tag);
|
|
|
|
[transaction
|
|
|
|
[transaction
|
|
|
|
enumerateKeysAndObjectsInCollection:TSStorageManagerSessionStoreCollection
|
|
|
|
enumerateKeysAndObjectsInCollection:TSStorageManagerSessionStoreCollection
|
|
|
|