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

Version 2.11.0 #128

Merged
merged 4 commits into from
Mar 16, 2018
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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

All notable changes to the LaunchDarkly iOS SDK will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org).

## [2.11.0] - 2018-03-15
### Added
- Support for enhanced feature streams, facilitating reduced SDK initialization times.

### Changed
- The `streamUrl` property on `LDConfig` now expects a path-less base URI.

## [2.10.1] - 2018-02-15
### Changed
- The minimum polling interval is now 5 minutes.
Expand Down
2 changes: 1 addition & 1 deletion Cartfile
Original file line number Diff line number Diff line change
@@ -1 +1 @@
github "launchdarkly/ios-eventsource"
github "launchdarkly/ios-eventsource" >= 3.2
2 changes: 1 addition & 1 deletion Cartfile.resolved
Original file line number Diff line number Diff line change
@@ -1 +1 @@
github "launchdarkly/ios-eventsource" "3.1.2"
github "launchdarkly/ios-eventsource" "3.2.0"
236 changes: 200 additions & 36 deletions Darkly.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0910"
LastUpgradeVersion = "0920"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0910"
LastUpgradeVersion = "0920"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0910"
LastUpgradeVersion = "0920"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0910"
LastUpgradeVersion = "0920"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
1 change: 1 addition & 0 deletions Darkly/DarklyConstants.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ extern NSString *const kLDFlagConfigChangedNotification;
extern NSString *const kLDServerConnectionUnavailableNotification;
extern NSString *const kLDClientUnauthorizedNotification;
extern NSString *const kLDBackgroundFetchInitiated;
extern NSString *const kHTTPMethodReport;
extern int const kCapacity;
extern int const kConnectionTimeout;
extern int const kDefaultFlushInterval;
Expand Down
5 changes: 3 additions & 2 deletions Darkly/DarklyConstants.m
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@

#import "DarklyConstants.h"

NSString * const kClientVersion = @"2.10.1";
NSString * const kClientVersion = @"2.11.0";
NSString * const kBaseUrl = @"https://app.launchdarkly.com";
NSString * const kEventsUrl = @"https://mobile.launchdarkly.com";
NSString * const kStreamUrl = @"https://clientstream.launchdarkly.com/mping";
NSString * const kStreamUrl = @"https://clientstream.launchdarkly.com";
NSString * const kNoMobileKeyExceptionName = @"NoMobileKeyDefinedException";
NSString * const kNoMobileKeyExceptionReason = @"A valid MobileKey must be provided";
NSString * const kNilConfigExceptionName = @"NilConfigException";
Expand All @@ -29,6 +29,7 @@
NSString * const kLDFlagConfigChangedNotification = @"Darkly.FlagConfigChangedNotification";
NSString * const kLDServerConnectionUnavailableNotification = @"Darkly.ServerConnectionUnavailableNotification";
NSString * const kLDClientUnauthorizedNotification = @"Darkly.LDClientUnauthorizedNotification";
NSString * const kHTTPMethodReport = @"REPORT";
int const kCapacity = 100;
int const kConnectionTimeout = 10;
int const kDefaultFlushInterval = 30;
Expand Down
134 changes: 130 additions & 4 deletions Darkly/LDClientManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
#import "NSDictionary+JSON.h"
#import <DarklyEventSource/LDEventSource.h>
#import "LDEvent+Unauthorized.h"
#import "LDEvent+EventTypes.h"

NSString * const kLDClientManagerStreamMethod = @"meval";

@interface LDClientManager()

Expand Down Expand Up @@ -135,11 +138,14 @@ - (void)configureEventSource {
DEBUG_LOGX(@"ClientManager aborting event source creation - event source running");
return;
}
eventSource = [LDEventSource eventSourceWithURL:[NSURL URLWithString:[LDClient sharedInstance].ldConfig.streamUrl] httpHeaders:[self httpHeadersForEventSource]];


eventSource = [self eventSourceForUser:[LDClient sharedInstance].ldUser config:[LDClient sharedInstance].ldConfig httpHeaders:[self httpHeadersForEventSource]];

[eventSource onMessage:^(LDEvent *event) {
if (![event.event isEqualToString:@"ping"]) { return; }
[self syncWithServerForConfig];
[self handlePingEvent:event];
[self handlePutEvent:event];
[self handlePatchEvent:event];
[self handleDeleteEvent:event];
}];

[eventSource onError:^(LDEvent *event) {
Expand All @@ -150,6 +156,126 @@ - (void)configureEventSource {
}
}

- (LDEventSource*)eventSourceForUser:(LDUserModel*)user config:(LDConfig*)config httpHeaders:(NSDictionary*)httpHeaders {
LDEventSource *eventSource;
if (config.useReport) {
eventSource = [LDEventSource eventSourceWithURL:[self eventSourceUrlForUser:user config:config]
httpHeaders:httpHeaders
connectMethod:kHTTPMethodReport
connectBody:[[[user dictionaryValueWithPrivateAttributesAndFlagConfig:NO] jsonString] dataUsingEncoding:NSUTF8StringEncoding]];
} else {
eventSource = [LDEventSource eventSourceWithURL:[self eventSourceUrlForUser:user config:config] httpHeaders:httpHeaders connectMethod:nil connectBody:nil];
}
return eventSource;
}

- (NSURL*)eventSourceUrlForUser:(LDUserModel *)user config:(LDConfig*)config {
NSString *eventStreamUrl = [config.streamUrl stringByAppendingPathComponent:kLDClientManagerStreamMethod];
if (!config.useReport) {
NSString *encodedUser = [LDUtil base64UrlEncodeString:[[user dictionaryValueWithPrivateAttributesAndFlagConfig:NO] jsonString]];
eventStreamUrl = [eventStreamUrl stringByAppendingPathComponent:encodedUser];
}
return [NSURL URLWithString:eventStreamUrl];
}

- (void)handlePingEvent:(LDEvent*)event {
if (![event.event isEqualToString:kLDEventTypePing]) { return; }
[self syncWithServerForConfig];
}

- (void)handlePutEvent:(LDEvent*)event {
if (![event.event isEqualToString:kLDEventTypePut]) { return; }
if (event.data.length == 0) {
DEBUG_LOGX(@"ClientManager aborted handlePutEvent - event contains no data");
[[NSNotificationCenter defaultCenter] postNotificationName:kLDUserNoChangeNotification object:nil];
return;
}
NSDictionary *newConfigDictionary = [NSJSONSerialization JSONObjectWithData:[event.data dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:nil];
if (!newConfigDictionary) {
DEBUG_LOGX(@"ClientManager aborted handlePutEvent - event contains json data could not be read");
[[NSNotificationCenter defaultCenter] postNotificationName:kLDUserNoChangeNotification object:nil];
return;
}

LDFlagConfigModel *newConfig = [[LDFlagConfigModel alloc] initWithDictionary:newConfigDictionary];
LDUserModel *user = [[LDClient sharedInstance] ldUser];

if ([user.config isEqualToConfig:newConfig]) {
DEBUG_LOGX(@"ClientManager handlePutEvent resulted in no change to the flag config");
[[NSNotificationCenter defaultCenter] postNotificationName:kLDUserNoChangeNotification object:nil];
return;
}

user.config = newConfig;
[[LDDataManager sharedManager] saveUser:user];
[[NSNotificationCenter defaultCenter] postNotificationName:kLDUserUpdatedNotification object:nil];
DEBUG_LOGX(@"ClientManager posted Darkly.UserUpdatedNotification following user config update from SSE put event");
}

- (void)handlePatchEvent:(LDEvent*)event {
if (![event.event isEqualToString:kLDEventTypePatch]) { return; }
if (event.data.length == 0) {
DEBUG_LOGX(@"ClientManager aborted handlePatchEvent - event contains no data");
[[NSNotificationCenter defaultCenter] postNotificationName:kLDUserNoChangeNotification object:nil];
return;
}
NSDictionary *patchDictionary = [NSJSONSerialization JSONObjectWithData:[event.data dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:nil];
if (!patchDictionary) {
DEBUG_LOGX(@"ClientManager aborted handlePatchEvent - event json data could not be read");
[[NSNotificationCenter defaultCenter] postNotificationName:kLDUserNoChangeNotification object:nil];
return;
}

LDUserModel *user = [[LDClient sharedInstance] ldUser];
NSDictionary *originalFlagConfig = user.config.featuresJsonDictionary;

[user.config addOrReplaceFromDictionary:patchDictionary];

if ([user.config hasFeaturesEqualToDictionary:originalFlagConfig]) {
DEBUG_LOGX(@"ClientManager handlePatchEvent resulted in no change to the flag config");
[[NSNotificationCenter defaultCenter] postNotificationName:kLDUserNoChangeNotification object:nil];
return;
}

[[LDDataManager sharedManager] saveUser:user];
[[NSNotificationCenter defaultCenter] postNotificationName:kLDUserUpdatedNotification object:nil];
DEBUG_LOGX(@"ClientManager posted Darkly.UserUpdatedNotification following user config update from SSE patch event");
}

- (void)handleDeleteEvent:(LDEvent*)event {
if (![event.event isEqualToString:kLDEventTypeDelete]) { return; }
if (event.data.length == 0) {
DEBUG_LOGX(@"ClientManager aborted handleDeleteEvent - event contains no data");
[[NSNotificationCenter defaultCenter] postNotificationName:kLDUserNoChangeNotification object:nil];
return;
}
NSDictionary *deleteDictionary = [NSJSONSerialization JSONObjectWithData:[event.data dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:nil];
if (!deleteDictionary) {
DEBUG_LOGX(@"ClientManager aborted handleDeleteEvent - event json data could not be read");
[[NSNotificationCenter defaultCenter] postNotificationName:kLDUserNoChangeNotification object:nil];
return;
}

LDUserModel *user = [[LDClient sharedInstance] ldUser];
NSDictionary *originalFlagConfig = user.config.featuresJsonDictionary;

[user.config deleteFromDictionary:deleteDictionary];

if ([user.config hasFeaturesEqualToDictionary:originalFlagConfig]) {
DEBUG_LOGX(@"ClientManager handleDeleteEvent resulted in no change to the flag config");
[[NSNotificationCenter defaultCenter] postNotificationName:kLDUserNoChangeNotification object:nil];
return;
}

[[LDDataManager sharedManager] saveUser:user];
[[NSNotificationCenter defaultCenter] postNotificationName:kLDUserUpdatedNotification object:nil];
DEBUG_LOGX(@"ClientManager posted Darkly.UserUpdatedNotification following user config update from SSE delete event");
}

- (void)postClientUnauthorizedNotification {
[[NSNotificationCenter defaultCenter] postNotificationName:kLDClientUnauthorizedNotification object:nil];
}

- (void)stopEventSource {
@synchronized (self) {
[eventSource close];
Expand Down
10 changes: 5 additions & 5 deletions Darkly/LDConfig.m
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ - (void)setEventsUrl:(NSString *)eventsUrl {
}

- (void)setCapacity:(NSNumber *)capacity {
if (capacity) {
if (capacity != nil) {
DEBUG_LOG(@"Set LDConfig capacity: %@", capacity);
_capacity = capacity;
} else {
Expand All @@ -73,7 +73,7 @@ - (void)setCapacity:(NSNumber *)capacity {
}

- (void)setConnectionTimeout:(NSNumber *)connectionTimeout {
if (connectionTimeout) {
if (connectionTimeout != nil) {
DEBUG_LOG(@"Set LDConfig timeout: %@", connectionTimeout);
_connectionTimeout = connectionTimeout;
} else {
Expand All @@ -83,7 +83,7 @@ - (void)setConnectionTimeout:(NSNumber *)connectionTimeout {
}

- (void)setFlushInterval:(NSNumber *)flushInterval {
if (flushInterval) {
if (flushInterval != nil) {
DEBUG_LOG(@"Set LDConfig flush interval: %@", flushInterval);
_flushInterval = flushInterval;
} else {
Expand All @@ -93,7 +93,7 @@ - (void)setFlushInterval:(NSNumber *)flushInterval {
}

- (void)setPollingInterval:(NSNumber *)pollingInterval {
if (pollingInterval) {
if (pollingInterval != nil) {
DEBUG_LOG(@"Set LDConfig polling interval: %@", pollingInterval);
_pollingInterval = [NSNumber numberWithInt:MAX(pollingInterval.intValue, kMinimumPollingInterval)];
} else {
Expand All @@ -103,7 +103,7 @@ - (void)setPollingInterval:(NSNumber *)pollingInterval {
}

- (void)setBackgroundFetchInterval:(NSNumber *)backgroundFetchInterval {
if (backgroundFetchInterval) {
if (backgroundFetchInterval != nil) {
DEBUG_LOG(@"Set LDConfig background fetch interval: %@", backgroundFetchInterval);
_backgroundFetchInterval = backgroundFetchInterval;
} else {
Expand Down
2 changes: 1 addition & 1 deletion Darkly/LDDataManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ -(LDUserModel *)findUserWithkey: (NSString *)key {
}

- (void)compareConfigForUser:(LDUserModel *)user withNewUser:(LDUserModel *)newUser {
for (NSString *key in [[newUser.config dictionaryValue] objectForKey:kFeaturesJsonDictionaryKey]) {
for (NSString *key in [newUser.config dictionaryValueIncludeNulls:NO]) {
if(user == nil || ![[newUser.config configFlagValue:key] isEqual:[user.config configFlagValue:key]]) {
[[NSNotificationCenter defaultCenter] postNotificationName:kLDFlagConfigChangedNotification object:nil userInfo:[NSDictionary dictionaryWithObject:key forKey:kFlagKey]];
}
Expand Down
18 changes: 18 additions & 0 deletions Darkly/LDEvent+EventTypes.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// LDEvent+EventTypes.h
// Darkly
//
// Created by Mark Pokorny on 2/5/18.
// Copyright © 2018 LaunchDarkly. All rights reserved.
//

#import <DarklyEventSource/LDEventSource.h>

extern NSString * const kLDEventTypePing;
extern NSString * const kLDEventTypePut;
extern NSString * const kLDEventTypePatch;
extern NSString * const kLDEventTypeDelete;

@interface LDEvent (EventTypes)

@end
18 changes: 18 additions & 0 deletions Darkly/LDEvent+EventTypes.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// LDEvent+EventTypes.m
// Darkly
//
// Created by Mark Pokorny on 2/5/18. +JMJ
// Copyright © 2018 LaunchDarkly. All rights reserved.
//

#import "LDEvent+EventTypes.h"

NSString * const kLDEventTypePing = @"ping";
NSString * const kLDEventTypePut = @"put";
NSString * const kLDEventTypePatch = @"patch";
NSString * const kLDEventTypeDelete = @"delete";

@implementation LDEvent (EventTypes)

@end
19 changes: 12 additions & 7 deletions Darkly/LDFlagConfigModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,23 @@
//

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

@interface LDFlagConfigModel : NSObject <NSCoding>

extern NSString * _Nullable const kFeaturesJsonDictionaryKey;
@property (nullable, nonatomic, strong) NSDictionary<NSString*, LDFlagConfigValue*> *featuresJsonDictionary;

@property (nullable, nonatomic, strong) NSDictionary *featuresJsonDictionary;
-(nullable id)initWithDictionary:(nullable NSDictionary*)dictionary;
-(nullable NSDictionary*)dictionaryValue;
-(nullable NSDictionary*)dictionaryValueIncludeNulls:(BOOL)includeNulls;

- (nonnull id)initWithDictionary:(nonnull NSDictionary *)dictionary;
-(nonnull NSDictionary *)dictionaryValue;
-(BOOL)doesConfigFlagExist:(nonnull NSString*)keyName;
-(nullable id)configFlagValue:(nonnull NSString*)keyName;
-(NSInteger)configFlagVersion:(nonnull NSString*)keyName;

-(nonnull NSObject*) configFlagValue: ( NSString * __nonnull )keyName;
-(BOOL) doesConfigFlagExist: ( NSString * __nonnull )keyName;
-(void)addOrReplaceFromDictionary:(nullable NSDictionary*)patch;
-(void)deleteFromDictionary:(nullable NSDictionary*)delete;

-(BOOL)isEqualToConfig:(nullable LDFlagConfigModel *)otherConfig;
-(BOOL)isEqualToConfig:(nullable LDFlagConfigModel*)otherConfig;
-(BOOL)hasFeaturesEqualToDictionary:(nullable NSDictionary*)otherDictionary;
@end
Loading