Upload by way of significant location change service.

Change-Id: I1793da66ce642bd896f1a41e464cb6e97356c7e1
This commit is contained in:
Nick O'Neill 2013-12-08 20:50:03 -08:00
parent 2fde7c11a0
commit 4e54a3515b
10 changed files with 124 additions and 56 deletions

View File

@ -71,8 +71,8 @@
D095AE4C1814B1B9008163F2 /* LACamliFile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LACamliFile.m; sourceTree = "<group>"; };
D095AE4D1814B1B9008163F2 /* LACamliClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LACamliClient.h; sourceTree = "<group>"; };
D095AE4E1814B1B9008163F2 /* LACamliClient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LACamliClient.m; sourceTree = "<group>"; };
D0AC216F18503A8E004BD4F3 /* CamliCollectionCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CamliCollectionCell.h; path = photobackup/CamliCollectionCell.h; sourceTree = "<group>"; };
D0AC217018503A8E004BD4F3 /* CamliCollectionCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CamliCollectionCell.m; path = photobackup/CamliCollectionCell.m; sourceTree = "<group>"; };
D0AC216F18503A8E004BD4F3 /* CamliCollectionCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CamliCollectionCell.h; sourceTree = "<group>"; };
D0AC217018503A8E004BD4F3 /* CamliCollectionCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CamliCollectionCell.m; sourceTree = "<group>"; };
D0AC217218503B0D004BD4F3 /* LACamliRecentFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LACamliRecentFile.h; sourceTree = "<group>"; };
D0AC217318503B0D004BD4F3 /* LACamliRecentFile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LACamliRecentFile.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -104,8 +104,6 @@
D095AE061814AF10008163F2 = {
isa = PBXGroup;
children = (
D0AC216F18503A8E004BD4F3 /* CamliCollectionCell.h */,
D0AC217018503A8E004BD4F3 /* CamliCollectionCell.m */,
D095AE181814AF10008163F2 /* photobackup */,
D095AE3A1814AF10008163F2 /* photobackupTests */,
D095AE111814AF10008163F2 /* Frameworks */,
@ -141,6 +139,8 @@
D095AE221814AF10008163F2 /* LAAppDelegate.m */,
D095AE2A1814AF10008163F2 /* LAViewController.h */,
D095AE2B1814AF10008163F2 /* LAViewController.m */,
D0AC216F18503A8E004BD4F3 /* CamliCollectionCell.h */,
D0AC217018503A8E004BD4F3 /* CamliCollectionCell.m */,
D095AE241814AF10008163F2 /* Main_iPhone.storyboard */,
D095AE271814AF10008163F2 /* Main_iPad.storyboard */,
D095AE2D1814AF10008163F2 /* Images.xcassets */,
@ -244,6 +244,13 @@
LastUpgradeCheck = 0500;
ORGANIZATIONNAME = "Nick O'Neill";
TargetAttributes = {
D095AE0E1814AF10008163F2 = {
SystemCapabilities = {
com.apple.BackgroundModes = {
enabled = 1;
};
};
};
D095AE321814AF10008163F2 = {
TestTargetID = D095AE0E1814AF10008163F2;
};

View File

@ -7,9 +7,19 @@
//
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import "LACamliClient.h"
@interface LAAppDelegate : UIResponder <UIApplicationDelegate>
@class ALAssetsLibrary;
@interface LAAppDelegate : UIResponder <UIApplicationDelegate,CLLocationManagerDelegate>
@property (strong, nonatomic) UIWindow *window;
@property CLLocationManager *locationManager;
@property LACamliClient *client;
// kicked out of the library if we don't have a reference and still want to play with the books
@property ALAssetsLibrary *library;
@end

View File

@ -7,15 +7,87 @@
//
#import "LAAppDelegate.h"
#import "LACamliFile.h"
#import <AssetsLibrary/AssetsLibrary.h>
@implementation LAAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
[self.locationManager startMonitoringSignificantLocationChanges];
NSString *credentialsPath = [[NSBundle mainBundle] pathForResource:@"credentials" ofType:@"plist"];
NSDictionary *credentials = [NSDictionary dictionaryWithContentsOfFile:credentialsPath];
NSAssert(credentials[@"camlistore_url"], @"no camlistore url specified");
NSAssert(credentials[@"camlistore_username"], @"no camlistore username specified");
NSAssert(credentials[@"camlistore_password"], @"no camlistore password specified");
self.client = [[LACamliClient alloc] initWithServer:[NSURL URLWithString:credentials[@"camlistore_url"]] username:credentials[@"camlistore_username"] andPassword:credentials[@"camlistore_password"]];
self.library = [[ALAssetsLibrary alloc] init];
return YES;
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *updatedLocation = [locations lastObject];
LALog(@"updated location: %@",updatedLocation);
NSString *documents = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString *updatesLocation = [documents stringByAppendingPathComponent:@"locations.plist"];
NSMutableArray *locationArchive = [NSMutableArray arrayWithContentsOfFile:updatesLocation];
if (!locationArchive) {
locationArchive = [NSMutableArray array];
}
[locationArchive addObject:[updatedLocation timestamp]];
[locationArchive writeToFile:updatesLocation atomically:YES];
if ([ALAssetsLibrary authorizationStatus] == ALAuthorizationStatusAuthorized) {
[self checkForUploads];
}
}
- (void)checkForUploads
{
NSInteger __block filesToUpload = 0;
UIBackgroundTaskIdentifier assetCheckID = [[UIApplication sharedApplication] beginBackgroundTaskWithName:@"assetCheck" expirationHandler:^{
LALog(@"asset check task expired");
}];
[self.library enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
[group enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
if (result && [result valueForProperty:ALAssetPropertyType] != ALAssetTypeVideo) { // enumerate returns null after the last item
LACamliFile *file = [[LACamliFile alloc] initWithAsset:result];
if (![self.client fileAlreadyUploaded:file]) {
filesToUpload++;
[self.client addFile:file withCompletion:^{
[UIApplication sharedApplication].applicationIconBadgeNumber--;
}];
} else {
LALog(@"file already uploaded: %@",file.blobRef);
}
}
}];
[UIApplication sharedApplication].applicationIconBadgeNumber = filesToUpload;
} failureBlock:^(NSError *error) {
LALog(@"failed enumerate: %@",error);
}];
[[UIApplication sharedApplication] endBackgroundTask:assetCheckID];
}
- (void)applicationWillResignActive:(UIApplication *)application
{
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.

View File

@ -22,6 +22,7 @@
@property NSOperationQueue *uploadQueue;
@property NSMutableArray *uploadedBlobRefs;
@property UIBackgroundTaskIdentifier backgroundID;
@property BOOL isAuthorized;
@property BOOL authorizing;
@ -31,7 +32,7 @@
- (void)discoveryWithUsername:(NSString *)user andPassword:(NSString *)pass;
- (BOOL)fileAlreadyUploaded:(LACamliFile *)file;
- (void)addFile:(LACamliFile *)file;
- (void)addFile:(LACamliFile *)file withCompletion:(void (^)())completion;
- (NSURL *)statUrl;

View File

@ -56,7 +56,7 @@
}
// starts uploading immediately
- (void)addFile:(LACamliFile *)file
- (void)addFile:(LACamliFile *)file withCompletion:(void (^)())completion
{
NSParameterAssert(file);
@ -73,6 +73,8 @@
LALog(@"finished op %@",file.blobRef);
[self.uploadedBlobRefs addObject:file.blobRef];
[self.uploadedBlobRefs writeToFile:[self uploadedBlobRefArchivePath] atomically:YES];
completion();
};
[self.uploadQueue addOperation:op];

View File

@ -14,6 +14,7 @@
@property LACamliClient *client;
@property LACamliFile *file;
@property UIBackgroundTaskIdentifier taskID;
@property (readonly) BOOL isExecuting;
@property (readonly) BOOL isFinished;

View File

@ -39,12 +39,19 @@ static NSString *const multipartBoundary = @"Qe43VdbVVaGtkkMd";
// request stats for each chunk, making sure the server doesn't already have the chunk
- (void)start
{
self.taskID =[[UIApplication sharedApplication] beginBackgroundTaskWithName:@"uploadtask" expirationHandler:^{
LALog(@"upload task expired");
}];
if (self.client.backgroundID) {
[[UIApplication sharedApplication] endBackgroundTask:self.client.backgroundID];
}
[self willChangeValueForKey:@"isExecuting"];
_isExecuting = YES;
[self didChangeValueForKey:@"isExecuting"];
LALog(@"stat");
NSMutableDictionary *params = [NSMutableDictionary dictionary];
[params setObject:[NSNumber numberWithInt:camliVersion] forKey:@"camliversion"];
@ -134,6 +141,7 @@ static NSString *const multipartBoundary = @"Qe43VdbVVaGtkkMd";
}];
[upload resume];
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend
@ -167,8 +175,14 @@ static NSString *const multipartBoundary = @"Qe43VdbVVaGtkkMd";
- (void)finished
{
self.client.backgroundID = [[UIApplication sharedApplication] beginBackgroundTaskWithName:@"queuesync" expirationHandler:^{
LALog(@"queue sync task expired");
}];
[[UIApplication sharedApplication] endBackgroundTask:self.taskID];
LALog(@"finished op %@",self.file.blobRef);
[self willChangeValueForKey:@"isExecuting"];
[self willChangeValueForKey:@"isFinished"];
@ -215,7 +229,7 @@ static NSString *const multipartBoundary = @"Qe43VdbVVaGtkkMd";
NSData *schemaData = [NSJSONSerialization dataWithJSONObject:schemaBlob options:NSJSONWritingPrettyPrinted error:nil];
LALog(@"schema: %@",[[NSString alloc] initWithData:schemaData encoding:NSUTF8StringEncoding]);
// LALog(@"schema: %@",[[NSString alloc] initWithData:schemaData encoding:NSUTF8StringEncoding]);
[data appendData:[[NSString stringWithFormat:@"--%@\r\n", multipartBoundary] dataUsingEncoding:NSUTF8StringEncoding]];
[data appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"json\"\r\n", [LACamliUtil blobRef:schemaData]] dataUsingEncoding:NSUTF8StringEncoding]];

View File

@ -7,14 +7,7 @@
//
#import <UIKit/UIKit.h>
#import "LACamliClient.h"
@class ALAssetsLibrary;
@interface LAViewController : UIViewController
@property LACamliClient *client;
// kicked out of the library if we don't have a reference and still want to play with the books
@property ALAssetsLibrary *library;
@end

View File

@ -7,8 +7,6 @@
//
#import "LAViewController.h"
#import "LACamliFile.h"
#import <AssetsLibrary/AssetsLibrary.h>
@interface LAViewController ()
@ -19,40 +17,6 @@
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *credentialsPath = [[NSBundle mainBundle] pathForResource:@"credentials" ofType:@"plist"];
NSDictionary *credentials = [NSDictionary dictionaryWithContentsOfFile:credentialsPath];
NSAssert(credentials[@"camlistore_url"], @"no camlistore url specified");
NSAssert(credentials[@"camlistore_username"], @"no camlistore username specified");
NSAssert(credentials[@"camlistore_password"], @"no camlistore password specified");
self.client = [[LACamliClient alloc] initWithServer:[NSURL URLWithString:credentials[@"camlistore_url"]] username:credentials[@"camlistore_username"] andPassword:credentials[@"camlistore_password"]];
NSUInteger __block filesToUpload = 0;
self.library = [[ALAssetsLibrary alloc] init];
[self.library enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
LALog(@"group: %@",group);
[group enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
LALog(@"asset: %@",result);
if (result && [result valueForProperty:ALAssetPropertyType] != ALAssetTypeVideo) { // enumerate returns null after the last item
LACamliFile *file = [[LACamliFile alloc] initWithAsset:result];
if (![self.client fileAlreadyUploaded:file]) {
filesToUpload++;
[self.client addFile:file];
} else {
LALog(@"file already uploaded: %@",file.blobRef);
}
}
}];
} failureBlock:^(NSError *error) {
LALog(@"failed enumerate: %@",error);
}];
// TODO: set badge number to filesToUpload
}
#pragma mark - collection methods

View File

@ -24,6 +24,10 @@
<string>1.0</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIBackgroundModes</key>
<array>
<string>location</string>
</array>
<key>UIMainStoryboardFile</key>
<string>Main_iPhone</string>
<key>UIMainStoryboardFile~ipad</key>