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: ensure batch array in the request payload is never empty #387

Merged
merged 4 commits into from
Sep 19, 2023
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
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
6003F58E195388D20070C39A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; };
6003F590195388D20070C39A /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58F195388D20070C39A /* CoreGraphics.framework */; };
6003F592195388D20070C39A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; };
ED0CA6DD2A7D049E00899C1C /* RudderConfig.plist in Resources */ = {isa = PBXBuildFile; fileRef = ED0CA6DA2A7D049E00899C1C /* RudderConfig.plist */; };
ED0CA6DE2A7D049E00899C1C /* SampleRudderConfig.plist in Resources */ = {isa = PBXBuildFile; fileRef = ED0CA6DB2A7D049E00899C1C /* SampleRudderConfig.plist */; };
ED0CA6DF2A7D049E00899C1C /* RudderConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0CA6DC2A7D049E00899C1C /* RudderConfig.swift */; };
ED7619FF2727E28800B086F4 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = ED7619ED2727E28700B086F4 /* InfoPlist.strings */; };
Expand All @@ -37,7 +36,6 @@
6003F591195388D20070C39A /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
6003F5AF195388D20070C39A /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
ED0CA6D62A7D048D00899C1C /* RudderSampleAppObjC-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RudderSampleAppObjC-Bridging-Header.h"; sourceTree = "<group>"; };
ED0CA6DA2A7D049E00899C1C /* RudderConfig.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = RudderConfig.plist; sourceTree = "<group>"; };
ED0CA6DB2A7D049E00899C1C /* SampleRudderConfig.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = SampleRudderConfig.plist; sourceTree = "<group>"; };
ED0CA6DC2A7D049E00899C1C /* RudderConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RudderConfig.swift; sourceTree = "<group>"; };
ED3B022F272A67AB000893AA /* RudderSampleAppObjC.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = RudderSampleAppObjC.entitlements; sourceTree = "<group>"; };
Expand Down Expand Up @@ -121,7 +119,6 @@
ED0CA6D92A7D049E00899C1C /* RudderConfig */ = {
isa = PBXGroup;
children = (
ED0CA6DA2A7D049E00899C1C /* RudderConfig.plist */,
ED0CA6DB2A7D049E00899C1C /* SampleRudderConfig.plist */,
ED0CA6DC2A7D049E00899C1C /* RudderConfig.swift */,
);
Expand Down Expand Up @@ -218,7 +215,6 @@
buildActionMask = 2147483647;
files = (
ED761A012727E28800B086F4 /* LaunchScreen.storyboard in Resources */,
ED0CA6DD2A7D049E00899C1C /* RudderConfig.plist in Resources */,
ED0CA6DE2A7D049E00899C1C /* SampleRudderConfig.plist in Resources */,
ED761A052727E28800B086F4 /* Images.xcassets in Resources */,
ED7619FF2727E28800B086F4 /* InfoPlist.strings in Resources */,
Expand Down
2 changes: 1 addition & 1 deletion Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@ SPEC CHECKSUMS:

PODFILE CHECKSUM: 799e2be1c19caac49a14db2f15e20e189c476219

COCOAPODS: 1.12.0
COCOAPODS: 1.11.3
2 changes: 2 additions & 0 deletions Sources/Classes/Headers/Public/RSUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ NS_ASSUME_NONNULL_BEGIN
+ (NSString* _Nullable) getDeviceId;
+ (BOOL)isFileExists:(NSString *)fileName;
+ (BOOL)removeFile:(NSString *)fileName;
+ (BOOL) isDBMessageEmpty:(RSDBMessage*)dbMessage;
+ (BOOL) isEmptyString:(NSString *)value;

extern unsigned int MAX_EVENT_SIZE;
extern unsigned int MAX_BATCH_SIZE;
Expand Down
29 changes: 21 additions & 8 deletions Sources/Classes/RSCloudModeManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,15 @@ - (void) startCloudModeProcessor {
[RSLogger logDebug:[[NSString alloc] initWithFormat:@"RSCloudModeManager: CloudModeProcessor: Payload: %@", payload]];
[RSLogger logInfo:[[NSString alloc] initWithFormat:@"RSCloudModeManager: CloudModeProcessor: EventCount: %lu", (unsigned long)dbMessage.messageIds.count]];
[RSMetricsReporter report:SDKMETRICS_CM_EVENT forMetricType:COUNT withProperties:@{SDKMETRICS_TYPE: SDKMETRICS_MESSAGES} andValue:(float)dbMessage.messages.count];
response = [strongSelf->networkManager sendNetworkRequest:payload toEndpoint:BATCH_ENDPOINT withRequestMethod:POST];
if (response.state == NETWORK_SUCCESS) {
[RSLogger logDebug:[[NSString alloc] initWithFormat:@"RSCloudModeManager: CloudModeProcessor: Updating status as CLOUDMODEPROCESSING DONE for events (%@)",[RSUtils getCSVString:dbMessage.messageIds]]];
[RSMetricsReporter report:SDKMETRICS_CM_ATTEMPT_SUCCESS forMetricType:COUNT withProperties:nil andValue:(float)dbMessage.messages.count];
[strongSelf->dbPersistentManager updateEventsWithIds:dbMessage.messageIds withStatus:CLOUD_MODE_PROCESSING_DONE];
[strongSelf->dbPersistentManager clearProcessedEventsFromDB];
sleepCount = 0;
if (payload != nil) {
response = [strongSelf->networkManager sendNetworkRequest:payload toEndpoint:BATCH_ENDPOINT withRequestMethod:POST];
if (response.state == NETWORK_SUCCESS) {
[RSLogger logDebug:[[NSString alloc] initWithFormat:@"RSCloudModeManager: CloudModeProcessor: Updating status as CLOUDMODEPROCESSING DONE for events (%@)",[RSUtils getCSVString:dbMessage.messageIds]]];
[RSMetricsReporter report:SDKMETRICS_CM_ATTEMPT_SUCCESS forMetricType:COUNT withProperties:nil andValue:(float)dbMessage.messages.count];
[strongSelf->dbPersistentManager updateEventsWithIds:dbMessage.messageIds withStatus:CLOUD_MODE_PROCESSING_DONE];
[strongSelf->dbPersistentManager clearProcessedEventsFromDB];
sleepCount = 0;
}
}
}
[strongSelf->lock unlock];
Expand All @@ -78,6 +80,10 @@ - (void) startCloudModeProcessor {
}

+ (NSString*) getPayloadFromMessages: (RSDBMessage*)dbMessage{
if ([RSUtils isDBMessageEmpty:dbMessage]) {
[RSLogger logDebug:@"Payload construction aborted because the dbMessage is empty."];
return nil;
}
NSMutableArray<NSString *>* messages = dbMessage.messages;
NSMutableArray<NSString *>* messageIds = dbMessage.messageIds;
NSMutableArray<NSString *> *batchMessageIds = [[NSMutableArray alloc] init];
Expand All @@ -90,6 +96,7 @@ + (NSString*) getPayloadFromMessages: (RSDBMessage*)dbMessage{
[json appendFormat:@"\"sentAt\":\"%@\",", sentAt];
[json appendString:@"\"batch\":["];
unsigned int totalBatchSize = [RSUtils getUTF8Length:json] + 2; // we add 2 characters at the end
NSMutableString* batchMessage = [[NSMutableString alloc] init];
for (int index = 0; index < messages.count; index++) {
NSMutableString* message = [[NSMutableString alloc] initWithString:messages[index]];
long length = message.length;
Expand All @@ -103,9 +110,15 @@ + (NSString*) getPayloadFromMessages: (RSDBMessage*)dbMessage{
[RSMetricsReporter report:SDKMETRICS_EVENTS_DISCARDED forMetricType:COUNT withProperties:@{SDKMETRICS_TYPE: SDKMETRICS_BATCH_SIZE_INVALID} andValue:1];
break;
}
[json appendString:message];
[batchMessage appendString:message];
[batchMessageIds addObject:messageIds[index]];
}
// When empty batch is sent to the server it trigger Invalid JSON error. Hence it is necessary to ensure that batch is not empty.
if ([RSUtils isEmptyString:batchMessage]) {
[RSLogger logDebug:@"Payload construction aborted because the batch message is empty."];
return nil;
}
[json appendString:batchMessage];
if([json characterAtIndex:[json length]-1] == ',') {
// remove trailing ','
[json deleteCharactersInRange:NSMakeRange([json length]-1, 1)];
Expand Down
3 changes: 3 additions & 0 deletions Sources/Classes/RSConfigBuilder.m
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ - (instancetype) withFlushQueueSize: (int) flushQueueSize {
if (config == nil) {
config = [[RSConfig alloc] init];
}
if (flushQueueSize < 1 || flushQueueSize > 100) {
return self;
}
config.flushQueueSize = flushQueueSize;
return self;
}
Expand Down
22 changes: 12 additions & 10 deletions Sources/Classes/RSFlushManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -60,16 +60,18 @@ - (void)flushSync {
batchDBMessage.messageIds = messageIds;
batchDBMessage.messages = messages;
NSString* payload = [RSCloudModeManager getPayloadFromMessages:batchDBMessage];
RSNetworkResponse* response = [self->networkManager sendNetworkRequest:payload toEndpoint:BATCH_ENDPOINT withRequestMethod:POST];
if( response.state == NETWORK_SUCCESS){
[RSLogger logDebug:[[NSString alloc] initWithFormat:@"RSFlushUtils: flushSync: Successfully sent batch %d/%d", i, numberOfBatches]];
[RSLogger logDebug:[[NSString alloc] initWithFormat:@"RSFlushUtils: flushSync: Clearing events of batch %d from DB", i]];
[self->dbPersistentManager updateEventsWithIds:batchDBMessage.messageIds withStatus:CLOUD_MODE_PROCESSING_DONE];
[self->dbPersistentManager clearProcessedEventsFromDB];
[_dbMessage.messages removeObjectsInArray:messages];
[_dbMessage.messageIds removeObjectsInArray:messageIds];
lastBatchFailed = NO;
break;
if (payload != nil) {
RSNetworkResponse* response = [self->networkManager sendNetworkRequest:payload toEndpoint:BATCH_ENDPOINT withRequestMethod:POST];
if( response.state == NETWORK_SUCCESS){
[RSLogger logDebug:[[NSString alloc] initWithFormat:@"RSFlushUtils: flushSync: Successfully sent batch %d/%d", i, numberOfBatches]];
[RSLogger logDebug:[[NSString alloc] initWithFormat:@"RSFlushUtils: flushSync: Clearing events of batch %d from DB", i]];
[self->dbPersistentManager updateEventsWithIds:batchDBMessage.messageIds withStatus:CLOUD_MODE_PROCESSING_DONE];
[self->dbPersistentManager clearProcessedEventsFromDB];
[_dbMessage.messages removeObjectsInArray:messages];
[_dbMessage.messageIds removeObjectsInArray:messageIds];
lastBatchFailed = NO;
break;
}
}
[RSLogger logDebug:[[NSString alloc] initWithFormat:@"RSFlushUtils: flushSync: Failed to send %d/%d, retrying again, %d retries left", i, numberOfBatches, retries]];
}
Expand Down
8 changes: 8 additions & 0 deletions Sources/Classes/RSUtils.m
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,14 @@ + (BOOL) isApplicationUpdated {
return (previousVersion && ![previousVersion isEqualToString:currentVersion]);
}

+ (BOOL) isDBMessageEmpty:(RSDBMessage*)dbMessage {
return ([dbMessage.messages count] == 0 || [dbMessage.messageIds count] == 0);
}

+ (BOOL) isEmptyString:(NSString*)value {
return (value == nil || value.length == 0);
}

unsigned int MAX_EVENT_SIZE = 32 * 1024; // 32 KB
unsigned int MAX_BATCH_SIZE = 500 * 1024; // 500 KB

Expand Down