Skip to content

Commit

Permalink
Merge pull request #588 from segmentio/dev
Browse files Browse the repository at this point in the history
Sprint 14
  • Loading branch information
f2prateek committed Aug 5, 2016
2 parents 3b5cf0a + 34b7269 commit 2b02144
Show file tree
Hide file tree
Showing 96 changed files with 3,465 additions and 1,129 deletions.
File renamed without changes.
Expand Up @@ -31,7 +31,7 @@
//


#import "NSData+GZIP.h"
#import "NSData+SEGGZIP.h"
#import <zlib.h>
#import <dlfcn.h>

Expand All @@ -56,13 +56,13 @@ - (NSData *)seg_gzippedDataWithCompressionLevel:(float)level
if (self.length == 0 || [self seg_isGzippedData]) {
return self;
}

void *libz = seg_libzOpen();
int (*deflateInit2_)(z_streamp, int, int, int, int, int, const char *, int) =
(int (*)(z_streamp, int, int, int, int, int, const char *, int))dlsym(libz, "deflateInit2_");
(int (*)(z_streamp, int, int, int, int, int, const char *, int))dlsym(libz, "deflateInit2_");
int (*deflate)(z_streamp, int) = (int (*)(z_streamp, int))dlsym(libz, "deflate");
int (*deflateEnd)(z_streamp) = (int (*)(z_streamp))dlsym(libz, "deflateEnd");

z_stream stream;
stream.zalloc = Z_NULL;
stream.zfree = Z_NULL;
Expand All @@ -71,9 +71,9 @@ - (NSData *)seg_gzippedDataWithCompressionLevel:(float)level
stream.next_in = (Bytef *)(void *)self.bytes;
stream.total_out = 0;
stream.avail_out = 0;

static const NSUInteger ChunkSize = 16384;

NSMutableData *output = nil;
int compression = (level < 0.0f) ? Z_DEFAULT_COMPRESSION : (int)(roundf(level * 9));
if (deflateInit2(&stream, compression, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY) == Z_OK) {
Expand All @@ -89,7 +89,7 @@ - (NSData *)seg_gzippedDataWithCompressionLevel:(float)level
deflateEnd(&stream);
output.length = stream.total_out;
}

return output;
}

Expand Down
18 changes: 0 additions & 18 deletions Analytics/Classes/Internal/SEGAnalyticsRequest.h

This file was deleted.

120 changes: 0 additions & 120 deletions Analytics/Classes/Internal/SEGAnalyticsRequest.m

This file was deleted.

1 change: 1 addition & 0 deletions Analytics/Classes/Internal/SEGAnalyticsUtils.h
@@ -1,6 +1,7 @@
#import <Foundation/Foundation.h>

NSURL *SEGAnalyticsURLForFilename(NSString *filename);
NSString *GenerateUUIDString();

// Date Utils
NSString *iso8601FormattedString(NSDate *date);
Expand Down
8 changes: 8 additions & 0 deletions Analytics/Classes/Internal/SEGAnalyticsUtils.m
Expand Up @@ -21,6 +21,14 @@
return [[NSURL alloc] initFileURLWithPath:[supportPath stringByAppendingPathComponent:filename]];
}

NSString *GenerateUUIDString()
{
CFUUIDRef theUUID = CFUUIDCreate(NULL);
NSString *UUIDString = (__bridge_transfer NSString *)CFUUIDCreateString(NULL, theUUID);
CFRelease(theUUID);
return UUIDString;
}

// Date Utils
NSString *iso8601FormattedString(NSDate *date)
{
Expand Down
23 changes: 23 additions & 0 deletions Analytics/Classes/Internal/SEGHTTPClient.h
@@ -0,0 +1,23 @@
#import <Foundation/Foundation.h>
#import "SEGAnalytics.h"


@interface SEGHTTPClient : NSObject

@property (nonatomic, strong) SEGRequestFactory requestFactory;

+ (SEGRequestFactory)defaultRequestFactory;

- (instancetype)initWithRequestFactory:(SEGRequestFactory)requestFactory;

/**
* Upload dictionary formatted as per https://segment.com/docs/sources/server/http/#batch.
* This method will convert the dictionary to json, gzip it and upload the data.
* It will respond with retry = YES if the batch should be reuploaded at a later time.
* It will ask to retry for json errors and 3xx/5xx codes, and not retry for 2xx/4xx response codes.
*/
- (NSURLSessionUploadTask *)upload:(NSDictionary *)batch forWriteKey:(NSString *)writeKey completionHandler:(void (^)(BOOL retry))completionHandler;

- (NSURLSessionDataTask *)settingsForWriteKey:(NSString *)writeKey completionHandler:(void (^)(BOOL success, NSDictionary *settings))completionHandler;

@end
141 changes: 141 additions & 0 deletions Analytics/Classes/Internal/SEGHTTPClient.m
@@ -0,0 +1,141 @@
#import "SEGHTTPClient.h"
#import "NSData+SEGGZIP.h"
#import "SEGAnalyticsUtils.h"


@implementation SEGHTTPClient

+ (NSMutableURLRequest * (^)(NSURL *))defaultRequestFactory
{
return ^(NSURL *url) {
return [NSMutableURLRequest requestWithURL:url];
};
}

- (instancetype)initWithRequestFactory:(SEGRequestFactory)requestFactory
{
if (self = [self init]) {
if (requestFactory == nil) {
self.requestFactory = [SEGHTTPClient defaultRequestFactory];
} else {
self.requestFactory = requestFactory;
}
}
return self;
}

- (NSString *)authorizationHeader:(NSString *)writeKey
{
NSString *rawHeader = [writeKey stringByAppendingString:@":"];
NSData *userPasswordData = [rawHeader dataUsingEncoding:NSUTF8StringEncoding];
return [userPasswordData base64EncodedStringWithOptions:0];
}

- (NSURLSessionUploadTask *)upload:(NSDictionary *)batch forWriteKey:(NSString *)writeKey completionHandler:(void (^)(BOOL retry))completionHandler
{
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
config.HTTPAdditionalHeaders = @{
@"Accept-Encoding" : @"gzip",
@"Content-Encoding" : @"gzip",
@"Content-Type" : @"application/json",
@"Authorization" : [@"Basic " stringByAppendingString:[self authorizationHeader:writeKey]],
};
NSURLSession *session = [NSURLSession sessionWithConfiguration:config];

NSURL *url = [NSURL URLWithString:@"https://api.segment.io/v1/batch"];
NSMutableURLRequest *request = self.requestFactory(url);
[request setHTTPMethod:@"POST"];

NSError *error = nil;
NSException *exception = nil;
NSData *payload = nil;
@try {
payload = [NSJSONSerialization dataWithJSONObject:batch options:0 error:&error];
}
@catch (NSException *exc) {
exception = exc;
}
if (error || exception) {
SEGLog(@"%@ Error serializing JSON for batch upload %@", self, error);
completionHandler(NO); // Don't retry this batch.
return nil;
}
NSData *gzippedPayload = [payload seg_gzippedData];

NSURLSessionUploadTask *task = [session uploadTaskWithRequest:request fromData:gzippedPayload completionHandler:^(NSData *_Nullable data, NSURLResponse *_Nullable response, NSError *_Nullable error) {
if (error) {
SEGLog(@"Error uploading request %@.", error);
completionHandler(YES);
return;
}

NSInteger code = ((NSHTTPURLResponse *)response).statusCode;
if (code < 300) {
// 2xx response codes.
completionHandler(NO);
return;
}
if (code < 400) {
// 3xx response codes.
SEGLog(@"Server responded with unexpected HTTP code %d.", code);
completionHandler(YES);
return;
}
if (code < 500) {
// 4xx response codes.
SEGLog(@"Server rejected payload with HTTP code %d.", code);
completionHandler(NO);
return;
}

// 5xx response codes.
SEGLog(@"Server error with HTTP code %d.", code);
completionHandler(YES);
}];
[task resume];
return task;
}

- (NSURLSessionDataTask *)settingsForWriteKey:(NSString *)writeKey completionHandler:(void (^)(BOOL success, NSDictionary *settings))completionHandler
{
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
config.HTTPAdditionalHeaders = @{
@"Accept-Encoding" : @"gzip"
};
NSURLSession *session = [NSURLSession sessionWithConfiguration:config];

NSString *rawURL = [NSString stringWithFormat:@"https://cdn.segment.com/v1/projects/%@/settings", writeKey];
NSURL *url = [NSURL URLWithString:rawURL];
NSMutableURLRequest *request = self.requestFactory(url);
[request setHTTPMethod:@"GET"];

NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *_Nullable data, NSURLResponse *_Nullable response, NSError *_Nullable error) {
if (error != nil) {
SEGLog(@"Error fetching settings %@.", error);
completionHandler(NO, nil);
return;
}

NSInteger code = ((NSHTTPURLResponse *)response).statusCode;
if (code > 300) {
SEGLog(@"Server responded with unexpected HTTP code %d.", code);
completionHandler(NO, nil);
return;
}

NSError *jsonError = nil;
id responseJson = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
if (jsonError != nil) {
SEGLog(@"Error deserializing response body %@.", jsonError);
completionHandler(NO, nil);
return;
}

// 2xx response codes.
completionHandler(YES, responseJson);
}];
[task resume];
return task;
}

@end
3 changes: 3 additions & 0 deletions Analytics/Classes/Internal/SEGReachability.m
Expand Up @@ -113,6 +113,7 @@ + (SEGReachability *)reachabilityWithHostname:(NSString *)hostname
SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithName(NULL, [hostname UTF8String]);
if (ref) {
id reachability = [[self alloc] initWithReachabilityRef:ref];
CFRelease(ref);

#if __has_feature(objc_arc)
return reachability;
Expand All @@ -129,6 +130,7 @@ + (SEGReachability *)reachabilityWithAddress:(const struct sockaddr_in *)hostAdd
SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)hostAddress);
if (ref) {
id reachability = [[self alloc] initWithReachabilityRef:ref];
CFRelease(ref);

#if __has_feature(objc_arc)
return reachability;
Expand Down Expand Up @@ -171,6 +173,7 @@ - (SEGReachability *)initWithReachabilityRef:(SCNetworkReachabilityRef)ref
if (self != nil) {
self.reachableOnWWAN = YES;
self.reachabilityRef = ref;
CFRetain(self.reachabilityRef);
}

return self;
Expand Down

0 comments on commit 2b02144

Please sign in to comment.