Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: added a persistence layer over keys stored in standard defaults by rudderstack #454

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ PODS:
- RSCrashReporter (= 1.0.1)
- RudderKit (= 1.4.0)
- RSCrashReporter (1.0.1)
- Rudder (1.25.0):
- Rudder (1.25.1):
- MetricsReporter (= 1.2.1)
- RudderKit (1.4.0)
- SQLCipher (4.5.4):
Expand Down Expand Up @@ -33,10 +33,10 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
MetricsReporter: 99596ee5003c69949ed2f50acc34aee83c42f843
RSCrashReporter: 6b8376ac729b0289ebe0908553e5f56d8171f313
Rudder: 959b31df6a700432d3535b7d115afe0840d7b6c4
Rudder: 34799a1be015f03d7073a919c4b3557cfde428d4
RudderKit: d9d6997696e1642b753d8bdf94e57af643a68f03
SQLCipher: 905b145f65f349f26da9e60a19901ad24adcd381

PODFILE CHECKSUM: b6937cee06e0633464427ff0d975d40e17419e9f

COCOAPODS: 1.14.3
COCOAPODS: 1.14.2
262 changes: 143 additions & 119 deletions Rudder.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,10 @@
onlyGenerateCoverageForSpecifiedTargets = "YES">
<Testables>
<TestableReference
skipped = "NO"
parallelizable = "YES">
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "ED04A23B29839DCC0080A88D"
BlueprintIdentifier = "ED99903A2A69103A00031B06"
BuildableName = "RudderTests-iOS.xctest"
BlueprintName = "RudderTests-iOS"
ReferencedContainer = "container:Rudder.xcodeproj">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@
shouldAutocreateTestPlan = "YES">
<Testables>
<TestableReference
skipped = "NO"
parallelizable = "YES">
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "ED99902C2A69102400031B06"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@
shouldAutocreateTestPlan = "YES">
<Testables>
<TestableReference
skipped = "NO"
parallelizable = "YES">
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "ED9990482A69104B00031B06"
Expand Down
22 changes: 22 additions & 0 deletions Sources/Classes/Headers/Public/RSDefaultsPersistence.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// RSDefaultsPersistence.h
// Rudder
//
// Created by Desu Sai Venkat on 30/01/24.
//

@interface RSDefaultsPersistence : NSObject {
NSMutableDictionary *data;
NSURL *fileURL;
dispatch_queue_t dataAccessQueue;
}

- (instancetype)init NS_UNAVAILABLE NS_SWIFT_UNAVAILABLE("Use `RSDefaultsPersistence.sharedInstance()` instead.");
+ (instancetype)sharedInstance;
- (void) copyStandardDefaultsToPersistenceIfNeeded;
- (void) clearState;
- (void)writeObject:(id)object forKey:(NSString *)key;
- (id)readObjectForKey:(NSString *)key;
- (void)removeObjectForKey:(NSString *)key;

@end
2 changes: 2 additions & 0 deletions Sources/Classes/Headers/Public/RSEventRepository.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#import "RSElementCache.h"
#import "RSCloudModeManager.h"
#import "RSDeviceModeManager.h"
#import "RSDefaultsPersistence.h"
#import "RSPreferenceManager.h"
#import "RSDBPersistentManager.h"
#import "RSDataResidencyManager.h"
Expand All @@ -37,6 +38,7 @@ NS_ASSUME_NONNULL_BEGIN
RSDataResidencyManager* dataResidencyManager;
RSServerConfigManager* configManager;
RSNetworkManager* networkManager;
RSDefaultsPersistence* defaultsPersistence;
RSPreferenceManager *preferenceManager;
RSCloudModeManager *cloudModeManager;
RSDeviceModeManager *deviceModeManager;
Expand Down
5 changes: 4 additions & 1 deletion Sources/Classes/Headers/Public/RSPreferenceManager.h
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
//
// RSPreferenceManager.h
// Pods-DummyTestProject
// Rudder
//
// Created by Arnab Pal on 27/01/20.
//

#import <Foundation/Foundation.h>
#import "RSDefaultsPersistence.h"

NS_ASSUME_NONNULL_BEGIN

Expand All @@ -25,6 +26,7 @@ extern NSString *const RSLastActiveTimestamp;
extern NSString *const RSSessionAutoTrackStatus;

+ (instancetype) getInstance;
+ (NSArray *) getPreferenceKeys;

- (void) updateLastUpdatedTime: (long) updatedTime;
- (long) getLastUpdatedTime;
Expand All @@ -41,6 +43,7 @@ extern NSString *const RSSessionAutoTrackStatus;
- (void) deleteBuildVersionCode;

- (void) performMigration;
- (void) restoreMissingDefaultsFromPersistence;

- (NSString* __nullable) getBuildNumber;
- (void) saveBuildNumber: (NSString* __nonnull) buildNumber;
Expand Down
2 changes: 2 additions & 0 deletions Sources/Classes/Headers/Public/RSUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ NS_ASSUME_NONNULL_BEGIN

+ (NSString*) getTimestamp;
+ (NSString *)getFilePath:(NSString *)fileName;
+ (NSURL *)getFileURL:(NSString *) fileName;
+ (long) getTimeStampLong;
+ (NSString*) getUniqueId;
+ (NSString*) getLocale;
Expand All @@ -42,6 +43,7 @@ NS_ASSUME_NONNULL_BEGIN
+ (BOOL) isApplicationUpdated;
+ (NSString* _Nullable) getDeviceId;
+ (BOOL)isFileExists:(NSString *)fileName;
+ (BOOL)doesFileExistsAtURL:(NSURL *)fileURL;
+ (BOOL)removeFile:(NSString *)fileName;
+ (BOOL) isDBMessageEmpty:(RSDBMessage*)dbMessage;
+ (BOOL) isEmptyString:(NSString *)value;
Expand Down
115 changes: 115 additions & 0 deletions Sources/Classes/RSDefaultsPersistence.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
//
// RSDefaultsPersistence.m
// Rudder
//
// Created by Desu Sai Venkat on 30/01/24.
//

#import <Foundation/Foundation.h>
#import "RSUtils.h"
#import "RSLogger.h"
#import "RSDefaultsPersistence.h"

static RSDefaultsPersistence *instance;
static NSString * const standardDefaultsCopied = @"standardDefaultsCopied";

@implementation RSDefaultsPersistence

+ (instancetype)sharedInstance {
if(instance == nil) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[self alloc] init];
});
}
return instance;
}

- (instancetype)init {
self = [super init];
if (self) {
data = [NSMutableDictionary dictionary];
fileURL = [RSUtils getFileURL:@"rsDefaultsPersistence.plist"];
dataAccessQueue = dispatch_queue_create("com.rudderstack.defaultspersistence", DISPATCH_QUEUE_SERIAL);
[self loadFromFile];
}
return self;
}

- (void)loadFromFile {
if ([RSUtils doesFileExistsAtURL:fileURL]) {
NSError *error = nil;
NSDictionary* dictFromFile = [NSMutableDictionary dictionaryWithContentsOfURL:fileURL error:&error];
if (error == nil && dictFromFile != nil) {
[data addEntriesFromDictionary:dictFromFile];
}
}
}

// this would be executed only once after the SDK has been updated from a version without DefaultsPersistence
// to a version with DefaultsPersistence to ensure that the persistence layer and standard defaults are in same state.
- (void)copyStandardDefaultsToPersistenceIfNeeded {
BOOL userDefaultsCopiedAlready = [self readObjectForKey:standardDefaultsCopied];
if(!userDefaultsCopiedAlready) {
[RSLogger logDebug:@"RSDefaultsPersistence: copyStandardDefaultsToPersistenceIfNeeded: Copying Standard Defaults to Persistence layer"];
NSArray* preferenceKeys = [RSPreferenceManager getPreferenceKeys];
for(NSString* key in preferenceKeys) {
id value = [[NSUserDefaults standardUserDefaults] objectForKey:key];
if(value != nil) {
[self writeObject:value forKey:key];
}
}
// Set the flag to indicate that standard defaults have been copied to the persistence layer
[self writeObject:@YES forKey:standardDefaultsCopied];
}
}

// the caller of this method should ensure that this is dispatched to the dataAccessQueue synchronously
- (void)writeToFile {
NSError* error = nil;
[data writeToURL:fileURL error:&error];
if (error != nil) {
[RSLogger logError: [NSString stringWithFormat:@"RSDefaultsPersistence: writeToFile: Error writing to file: %@", error]];
}
}

- (void) writeToFileSync {
dispatch_sync(dataAccessQueue, ^{
[self writeToFile];
});
}

- (void)writeObject:(id)object forKey:(NSString *)key {
dispatch_sync(dataAccessQueue, ^{
if (object && key) {
data[key] = object;
[self writeToFile];
}
});
}

- (id)readObjectForKey:(NSString *)key {
__block id result;
dispatch_sync(dataAccessQueue, ^{
result = data[key];
});
return result;

}

- (void)removeObjectForKey:(NSString *)key {
dispatch_sync(dataAccessQueue, ^{
[data removeObjectForKey:key];
[self writeToFile];
});
}

// for testing purpose only
- (void) clearState {
dispatch_sync(dataAccessQueue, ^{
[data removeAllObjects];
[self writeToFile];
});
}

@end
5 changes: 5 additions & 0 deletions Sources/Classes/RSEventRepository.m
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,14 @@ - (instancetype)init:(NSString*)_writeKey config:(RSConfig*)_config client:(RSCl

self->authToken = [RSUtils getBase64EncodedString: [[NSString alloc] initWithFormat:@"%@:", self->writeKey]];

[RSLogger logDebug:@"EventRepository: Initiating DefaultsPersistence"];
self->defaultsPersistence = [RSDefaultsPersistence sharedInstance];
[self->defaultsPersistence copyStandardDefaultsToPersistenceIfNeeded];

[RSLogger logDebug:@"EventRepository: Initiating RSPreferenceManager"];
self->preferenceManager = [RSPreferenceManager getInstance];
[self->preferenceManager performMigration];
[self->preferenceManager restoreMissingDefaultsFromPersistence];

[self clearAnonymousIdIfRequired];

Expand Down
Loading
Loading