Skip to content

Commit

Permalink
Adapting PDKHttpTransmitter to be more easily subclassed.
Browse files Browse the repository at this point in the history
* Cleaning up Clang warnings.
  • Loading branch information
audaciouscode committed Jun 21, 2017
1 parent 147d9c8 commit af7dc30
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 89 deletions.
12 changes: 6 additions & 6 deletions PassiveDataKit.xcodeproj/project.pbxproj
Expand Up @@ -32,7 +32,7 @@
389DE4BC1EF726BB009C8B27 /* Mixpanel.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 389DE4B31EF726B2009C8B27 /* Mixpanel.framework */; };
389DE4D21EF7492C009C8B27 /* PDKHttpTransmitter.h in Headers */ = {isa = PBXBuildFile; fileRef = 389DE4D01EF7492C009C8B27 /* PDKHttpTransmitter.h */; settings = {ATTRIBUTES = (Public, ); }; };
389DE4D31EF7492C009C8B27 /* PDKHttpTransmitter.m in Sources */ = {isa = PBXBuildFile; fileRef = 389DE4D11EF7492C009C8B27 /* PDKHttpTransmitter.m */; };
389DE4D61EF74DDA009C8B27 /* NSString+RAInflections.h in Headers */ = {isa = PBXBuildFile; fileRef = 389DE4D41EF74DDA009C8B27 /* NSString+RAInflections.h */; };
389DE4D61EF74DDA009C8B27 /* NSString+RAInflections.h in Headers */ = {isa = PBXBuildFile; fileRef = 389DE4D41EF74DDA009C8B27 /* NSString+RAInflections.h */; settings = {ATTRIBUTES = (Public, ); }; };
389DE4D71EF74DDA009C8B27 /* NSString+RAInflections.m in Sources */ = {isa = PBXBuildFile; fileRef = 389DE4D51EF74DDA009C8B27 /* NSString+RAInflections.m */; };
389DE4DE1EF75ADB009C8B27 /* PDKBaseGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = 389DE4DC1EF75ADB009C8B27 /* PDKBaseGenerator.h */; };
389DE4DF1EF75ADB009C8B27 /* PDKBaseGenerator.m in Sources */ = {isa = PBXBuildFile; fileRef = 389DE4DD1EF75ADB009C8B27 /* PDKBaseGenerator.m */; };
Expand All @@ -53,9 +53,9 @@
38C666E11D038A8E00E6A6C8 /* PDKAFNetworkReachabilityManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 38C666C01D038A8E00E6A6C8 /* PDKAFNetworkReachabilityManager.m */; };
38C666E21D038A8E00E6A6C8 /* PDKAFSecurityPolicy.h in Headers */ = {isa = PBXBuildFile; fileRef = 38C666C11D038A8E00E6A6C8 /* PDKAFSecurityPolicy.h */; };
38C666E31D038A8E00E6A6C8 /* PDKAFSecurityPolicy.m in Sources */ = {isa = PBXBuildFile; fileRef = 38C666C21D038A8E00E6A6C8 /* PDKAFSecurityPolicy.m */; };
38C666E41D038A8E00E6A6C8 /* PDKAFURLRequestSerialization.h in Headers */ = {isa = PBXBuildFile; fileRef = 38C666C31D038A8E00E6A6C8 /* PDKAFURLRequestSerialization.h */; };
38C666E41D038A8E00E6A6C8 /* PDKAFURLRequestSerialization.h in Headers */ = {isa = PBXBuildFile; fileRef = 38C666C31D038A8E00E6A6C8 /* PDKAFURLRequestSerialization.h */; settings = {ATTRIBUTES = (Public, ); }; };
38C666E51D038A8E00E6A6C8 /* PDKAFURLRequestSerialization.m in Sources */ = {isa = PBXBuildFile; fileRef = 38C666C41D038A8E00E6A6C8 /* PDKAFURLRequestSerialization.m */; };
38C666E61D038A8E00E6A6C8 /* PDKAFURLResponseSerialization.h in Headers */ = {isa = PBXBuildFile; fileRef = 38C666C51D038A8E00E6A6C8 /* PDKAFURLResponseSerialization.h */; };
38C666E61D038A8E00E6A6C8 /* PDKAFURLResponseSerialization.h in Headers */ = {isa = PBXBuildFile; fileRef = 38C666C51D038A8E00E6A6C8 /* PDKAFURLResponseSerialization.h */; settings = {ATTRIBUTES = (Public, ); }; };
38C666E71D038A8E00E6A6C8 /* PDKAFURLResponseSerialization.m in Sources */ = {isa = PBXBuildFile; fileRef = 38C666C61D038A8E00E6A6C8 /* PDKAFURLResponseSerialization.m */; };
38C666E81D038A8E00E6A6C8 /* PDKAFURLSessionManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 38C666C71D038A8E00E6A6C8 /* PDKAFURLSessionManager.h */; };
38C666E91D038A8E00E6A6C8 /* PDKAFURLSessionManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 38C666C81D038A8E00E6A6C8 /* PDKAFURLSessionManager.m */; };
Expand Down Expand Up @@ -434,16 +434,17 @@
388D5E401EF76CD500C9A2A2 /* PassiveDataKit-Shared.h in Headers */,
3842F7351CDA2021007F843D /* PassiveDataKit.h in Headers */,
389DE4D21EF7492C009C8B27 /* PDKHttpTransmitter.h in Headers */,
389DE4D61EF74DDA009C8B27 /* NSString+RAInflections.h in Headers */,
38C666E61D038A8E00E6A6C8 /* PDKAFURLResponseSerialization.h in Headers */,
38C666E41D038A8E00E6A6C8 /* PDKAFURLRequestSerialization.h in Headers */,
38C666D91D038A8E00E6A6C8 /* PDKAFHTTPSessionManager.h in Headers */,
38A6523C1CDA2D9B00AE8B3B /* PDKLocationGenerator.h in Headers */,
383ECC6A1D1F82F5004E0B2B /* PDKMixpanelEventGenerator.h in Headers */,
383ECC661D1F816D004E0B2B /* PDKEventsGenerator.h in Headers */,
38DC949F1D2711C600552259 /* PDKGooglePlacesGenerator.h in Headers */,
38C666E41D038A8E00E6A6C8 /* PDKAFURLRequestSerialization.h in Headers */,
38C666E01D038A8E00E6A6C8 /* PDKAFNetworkReachabilityManager.h in Headers */,
38C666E21D038A8E00E6A6C8 /* PDKAFSecurityPolicy.h in Headers */,
38C666EA1D038A8E00E6A6C8 /* UIActivityIndicatorView+PDKAFNetworking.h in Headers */,
389DE4D61EF74DDA009C8B27 /* NSString+RAInflections.h in Headers */,
38C666F11D038A8E00E6A6C8 /* UIKit+PDKAFNetworking.h in Headers */,
389DE4DE1EF75ADB009C8B27 /* PDKBaseGenerator.h in Headers */,
38C666E81D038A8E00E6A6C8 /* PDKAFURLSessionManager.h in Headers */,
Expand All @@ -458,7 +459,6 @@
38C666DB1D038A8E00E6A6C8 /* PDKAFImageDownloader.h in Headers */,
38C666EC1D038A8E00E6A6C8 /* UIButton+PDKAFNetworking.h in Headers */,
38C666F21D038A8E00E6A6C8 /* UIProgressView+PDKAFNetworking.h in Headers */,
38C666E61D038A8E00E6A6C8 /* PDKAFURLResponseSerialization.h in Headers */,
38C666F41D038A8E00E6A6C8 /* UIRefreshControl+PDKAFNetworking.h in Headers */,
383ECC6E1D1F9915004E0B2B /* PDKLocationAnnotation.h in Headers */,
38C666D71D038A8E00E6A6C8 /* PDKAFAutoPurgingImageCache.h in Headers */,
Expand Down
11 changes: 8 additions & 3 deletions PassiveDataKit/PDKDataReportViewController.m
Expand Up @@ -70,7 +70,7 @@ - (void) loadVisualization:(NSString *) generator {
} else {
Class generatorClass = NSClassFromString(generator);

id<PDKGenerator> generator = [generatorClass sharedInstance];
id generator = [generatorClass sharedInstance];

if (generatorClass != nil) {
if ([generatorClass respondsToSelector:@selector(visualizationForSize:)]) {
Expand Down Expand Up @@ -196,8 +196,13 @@ - (UIViewController *) detailsControllerForGenerator:(NSString *) key {
Class generatorClass = NSClassFromString(key);

if (generatorClass != nil) {
if ([generatorClass respondsToSelector:@selector(detailsController)]) {
controller = [generatorClass performSelector:@selector(detailsController)];
SEL details = NSSelectorFromString(@"detailsController");

if ([generatorClass respondsToSelector:details]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
controller = [generatorClass performSelector:details];
#pragma clang diagnostic pop
}
}
return controller;
Expand Down
12 changes: 12 additions & 0 deletions PassiveDataKit/PDKHttpTransmitter.h
Expand Up @@ -7,13 +7,25 @@
//

#import "PassiveDataKit.h"
#import "NSString+RAInflections.h"

#define PDK_SOURCE_KEY @"source"
#define PDK_TRANSMITTER_ID_KEY @"transmitter-id"
#define PDK_TRANSMITTER_UPLOAD_URL_KEY @"upload-url"
#define PDK_TRANSMITTER_REQUIRE_CHARGING_KEY @"require-charging"
#define PDK_TRANSMITTER_REQUIRE_WIFI_KEY @"require-wifi"

#define PDK_METADATA_KEY @"passive-data-metadata"
#define PDK_GENERATOR_ID_KEY @"generator-id"
#define PDK_GENERATOR_KEY @"generator"
#define PDK_TIMESTAMP_KEY @"timestamp"

#define PDK_DEFAULT_TRANSMITTER_ID @"http-transmitter"

@interface PDKHttpTransmitter : NSObject<PDKTransmitter, PDKDataListener>

@property NSString * source;
@property NSString * transmitterId;
@property NSURL * uploadUrl;

@end
171 changes: 91 additions & 80 deletions PassiveDataKit/PDKHttpTransmitter.m
Expand Up @@ -9,19 +9,10 @@
#import <SystemConfiguration/SystemConfiguration.h>
#import <sqlite3.h>

#import "NSString+RAInflections.h"

#import "PDKAFURLSessionManager.h"

#import "PDKHttpTransmitter.h"

#define PDK_METADATA_KEY @"passive-data-metadata"
#define PDK_GENERATOR_ID_KEY @"generator-id"
#define PDK_GENERATOR_KEY @"generator"
#define PDK_TIMESTAMP_KEY @"timestamp"

#define PDK_DEFAULT_TRANSMITTER_ID @"http-transmitter"

typedef enum {
ConnectionTypeUnknown,
ConnectionTypeNone,
Expand All @@ -31,9 +22,6 @@

@interface PDKHttpTransmitter ()

@property NSString * source;
@property NSString * transmitterId;
@property NSURL * uploadUrl;
@property BOOL requireCharging;
@property BOOL requireWiFi;

Expand Down Expand Up @@ -177,6 +165,21 @@ - (void) transmit:(BOOL) force completionHandler:(void (^)(UIBackgroundFetchResu
[self transmitReadings:0 completionHandler:completionHandler];
}

- (NSURLRequest *) uploadRequestForPayload:(NSArray *) payload {
NSMutableURLRequest * request = [[PDKAFJSONRequestSerializer serializer] requestWithMethod:@"CREATE"
URLString:[self.uploadUrl description]
parameters:payload
error:nil];
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];

return request;
}

- (NSUInteger) payloadSize {
return 16;
}

- (void) transmitReadings:(NSUInteger) uploadWindow completionHandler:(void (^)(UIBackgroundFetchResult result)) completionHandler {
if (uploadWindow == 0) {
uploadWindow = 8; //!OCLINT
Expand All @@ -186,7 +189,7 @@ - (void) transmitReadings:(NSUInteger) uploadWindow completionHandler:(void (^)(

sqlite3_stmt * statement = NULL;

NSString * querySQL = @"SELECT D.id, D.properties FROM data D WHERE (D.timestamp < ?) LIMIT 16";
NSString * querySQL = [NSString stringWithFormat:@"SELECT D.id, D.properties FROM data D WHERE (D.timestamp < ?) LIMIT %d", (int) [self payloadSize]];

const char * query_stmt = [querySQL UTF8String];

Expand Down Expand Up @@ -224,65 +227,62 @@ - (void) transmitReadings:(NSUInteger) uploadWindow completionHandler:(void (^)(

sqlite3_finalize(statement);

NSMutableURLRequest *req = [[PDKAFJSONRequestSerializer serializer] requestWithMethod:@"CREATE"
URLString:[self.uploadUrl description]
parameters:payload
error:nil];
[req setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
[req setValue:@"application/json" forHTTPHeaderField:@"Accept"];

NSLog(@"UPLOADING PAYLOAD: %@", payload);

PDKAFURLSessionManager * manager = [[PDKAFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
NSURLRequest * request = [self uploadRequestForPayload:payload];

[[manager dataTaskWithRequest:req
uploadProgress:nil
downloadProgress:nil
completionHandler:^(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) {
if ([responseObject containsObject:@"Data bundle added successfully, and ready for processing."] == NO) {
NSLog(@"Invalid response: %@", responseObject);
}
else if (error == nil) {
for (NSNumber * identifier in uploaded) {
sqlite3_stmt * deleteStatement = NULL;

NSString * deleteSQL = @"DELETE FROM data WHERE (id = ?)";

const char * delete_stmt = [deleteSQL UTF8String];

if (sqlite3_prepare_v2(self.database, delete_stmt, -1, &deleteStatement, NULL) == SQLITE_OK)
{
sqlite3_bind_int(deleteStatement, 1, [identifier intValue]);
if (request != nil) {
NSLog(@"UPLOADING PAYLOAD: %@", payload);

PDKAFURLSessionManager * manager = [[PDKAFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];

[[manager dataTaskWithRequest:request
uploadProgress:nil
downloadProgress:nil
completionHandler:^(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) {
if ([responseObject containsObject:@"Data bundle added successfully, and ready for processing."] == NO) {
NSLog(@"Invalid response: %@", responseObject);
}
else if (error == nil) {
for (NSNumber * identifier in uploaded) {
sqlite3_stmt * deleteStatement = NULL;

while (sqlite3_step(deleteStatement) == SQLITE_ROW) { //!OCLINT
NSString * deleteSQL = @"DELETE FROM data WHERE (id = ?)";

const char * delete_stmt = [deleteSQL UTF8String];

if (sqlite3_prepare_v2(self.database, delete_stmt, -1, &deleteStatement, NULL) == SQLITE_OK)
{
sqlite3_bind_int(deleteStatement, 1, [identifier intValue]);

while (sqlite3_step(deleteStatement) == SQLITE_ROW) { //!OCLINT

}

sqlite3_finalize(deleteStatement);
} else {
if (completionHandler != nil) {
completionHandler(UIBackgroundFetchResultFailed);
}

NSLog(@"Error while deleting data. '%s'", sqlite3_errmsg(self.database));

return;
}

sqlite3_finalize(deleteStatement);
}

NSTimeInterval interval = [NSDate date].timeIntervalSince1970 - now;

if (uploadWindow > 0 && interval > uploadWindow && uploaded.count > 0) {
[self transmitReadings:(uploadWindow - interval) completionHandler:completionHandler];
} else {
if (completionHandler != nil) {
completionHandler(UIBackgroundFetchResultFailed);
completionHandler(UIBackgroundFetchResultNewData);
}

NSLog(@"Error while deleting data. '%s'", sqlite3_errmsg(self.database));

return;

}
}

NSTimeInterval interval = [NSDate date].timeIntervalSince1970 - now;

if (uploadWindow > 0 && interval > uploadWindow && uploaded.count > 0) {
[self transmitReadings:(uploadWindow - interval) completionHandler:completionHandler];
} else {
if (completionHandler != nil) {
completionHandler(UIBackgroundFetchResultNewData);
}

}
}

}] resume];
}] resume];
}
}
}

Expand All @@ -294,9 +294,9 @@ - (NSUInteger) transmittedSize {
return -1;
}

- (void) receivedData:(NSDictionary *) data forGenerator:(PDKDataGenerator) dataGenerator {
NSMutableDictionary * toStore = [NSMutableDictionary dictionaryWithDictionary:data];
- (NSDictionary *) processIncomingDataPoint:(NSDictionary *) dataPoint forGenerator:(PDKDataGenerator) dataGenerator {
NSMutableDictionary * toStore = [NSMutableDictionary dictionaryWithDictionary:dataPoint];

if (toStore[PDK_METADATA_KEY] == nil) {
NSMutableDictionary * metadata = [NSMutableDictionary dictionary];

Expand All @@ -310,30 +310,41 @@ - (void) receivedData:(NSDictionary *) data forGenerator:(PDKDataGenerator) data
} else {
metadata[PDK_SOURCE_KEY] = [[PassiveDataKit sharedInstance] identifierForUser];
}

metadata[PDK_TIMESTAMP_KEY] = [NSNumber numberWithDouble:[NSDate date].timeIntervalSince1970];

toStore[PDK_METADATA_KEY] = metadata;
}

return toStore;
}


- (void) receivedData:(NSDictionary *) dataPoint forGenerator:(PDKDataGenerator) dataGenerator {
NSDictionary * toStore = [self processIncomingDataPoint:dataPoint forGenerator:dataGenerator];

sqlite3_stmt * stmt;

NSString * insert = @"INSERT INTO data (timestamp, properties) VALUES (?, ?);";

if(sqlite3_prepare_v2(self.database, [insert UTF8String], -1, &stmt, NULL) == SQLITE_OK) {
sqlite3_bind_double(stmt, 1, [toStore[PDK_METADATA_KEY][PDK_TIMESTAMP_KEY] doubleValue]);
if (toStore != nil) {
NSLog(@"STORING: %@", toStore);

NSError * err = nil;
NSData * jsonData = [NSJSONSerialization dataWithJSONObject:toStore options:0 error:&err];
NSString * jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
sqlite3_stmt * stmt;

sqlite3_bind_text(stmt, 2, [jsonString UTF8String], -1, SQLITE_TRANSIENT);
NSString * insert = @"INSERT INTO data (timestamp, properties) VALUES (?, ?);";

if (SQLITE_DONE != sqlite3_step(stmt)) {
NSLog(@"Error while inserting data. '%s'", sqlite3_errmsg(self.database));
if(sqlite3_prepare_v2(self.database, [insert UTF8String], -1, &stmt, NULL) == SQLITE_OK) {
sqlite3_bind_double(stmt, 1, [toStore[PDK_METADATA_KEY][PDK_TIMESTAMP_KEY] doubleValue]);

NSError * err = nil;
NSData * jsonData = [NSJSONSerialization dataWithJSONObject:toStore options:0 error:&err];
NSString * jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];

sqlite3_bind_text(stmt, 2, [jsonString UTF8String], -1, SQLITE_TRANSIENT);

if (SQLITE_DONE != sqlite3_step(stmt)) {
NSLog(@"Error while inserting data. '%s'", sqlite3_errmsg(self.database));
}

sqlite3_finalize(stmt);
}

sqlite3_finalize(stmt);
}
}

Expand Down
2 changes: 2 additions & 0 deletions PassiveDataKit/PassiveDataKit-Shared.h
Expand Up @@ -10,3 +10,5 @@ FOUNDATION_EXPORT const unsigned char PassiveDataKit_SharedVersionString[];

#import "PassiveDataKit.h"
#import "PDKHttpTransmitter.h"

#import "PDKAFURLRequestSerialization.h"

0 comments on commit af7dc30

Please sign in to comment.