github.com/olivere/camlistore@v0.0.0-20140121221811-1b7ac2da0199/clients/ios-objc/photobackup/LACamliClient/LACamliClient.m (about)

     1  //
     2  //  LACamliClient.m
     3  //
     4  //  Created by Nick O'Neill on 1/10/13.
     5  //  Copyright (c) 2013 The Camlistore Authors. All rights reserved.
     6  //
     7  
     8  #import "LACamliClient.h"
     9  #import "LACamliUploadOperation.h"
    10  #import "LACamliFile.h"
    11  #import "LACamliUtil.h"
    12  
    13  @implementation LACamliClient
    14  
    15  NSString *const CamliNotificationUploadStart = @"camli-upload-start";
    16  NSString *const CamliNotificationUploadProgress = @"camli-upload-progress";
    17  NSString *const CamliNotificationUploadEnd = @"camli-upload-end";
    18  
    19  - (id)initWithServer:(NSURL *)server username:(NSString *)username andPassword:(NSString *)password
    20  {
    21      NSParameterAssert(server);
    22      NSParameterAssert(username);
    23      NSParameterAssert(password);
    24  
    25      if (self = [super init]) {
    26          self.serverURL = server;
    27          self.username = username;
    28          self.password = password;
    29          
    30          if ([[NSFileManager defaultManager] fileExistsAtPath:[self uploadedBlobRefArchivePath]]) {
    31              self.uploadedBlobRefs = [NSMutableArray arrayWithContentsOfFile:[self uploadedBlobRefArchivePath]];
    32          }
    33          if (!self.uploadedBlobRefs) {
    34              self.uploadedBlobRefs = [NSMutableArray array];
    35          }
    36          [LACamliUtil logText:@[@"uploads in cache: ",[NSString stringWithFormat:@"%d",[_uploadedBlobRefs count]]]];
    37          
    38          self.uploadQueue = [[NSOperationQueue alloc] init];
    39          self.uploadQueue.maxConcurrentOperationCount = 1;
    40          self.totalUploads = 0;
    41  
    42          self.isAuthorized = false;
    43          self.authorizing = false;
    44          
    45          _sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
    46          _sessionConfig.HTTPAdditionalHeaders = @{@"Authorization": [NSString stringWithFormat:@"Basic %@",[self encodedAuth]]};
    47      }
    48      
    49      return self;
    50  }
    51  
    52  #pragma mark - ready state
    53  
    54  - (BOOL)readyToUpload
    55  {
    56      // can't upload if we don't have credentials
    57      if (!self.username || !self.password || !self.serverURL) {
    58          [LACamliUtil logText:@[@"not ready: no u/p/s"]];
    59          return NO;
    60      }
    61  
    62      // don't want to start a new upload if we're already going
    63      if ([self.uploadQueue operationCount] > 0) {
    64          [LACamliUtil logText:@[@"not ready: already uploading"]];
    65          return NO;
    66      }
    67  
    68      [LACamliUtil logText:@[@"starting upload"]];
    69      return YES;
    70  }
    71  
    72  #pragma mark - discovery
    73  
    74  - (void)discoveryWithUsername:(NSString *)user andPassword:(NSString *)pass
    75  {
    76      [LACamliUtil statusText:@[@"discovering..."]];
    77      self.authorizing = YES;
    78  
    79      NSURLSessionConfiguration *discoverConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
    80      discoverConfig.HTTPAdditionalHeaders = @{@"Accept": @"text/x-camli-configuration", @"Authorization": [NSString stringWithFormat:@"Basic %@",[self encodedAuth]]};
    81      NSURLSession *discoverSession = [NSURLSession sessionWithConfiguration:discoverConfig delegate:self delegateQueue:nil];
    82  
    83      NSURLSessionDataTask *data = [discoverSession dataTaskWithURL:self.serverURL completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    84  
    85          if (error) {
    86              LALog(@"error discovery: %@",error);
    87              [LACamliUtil errorText:@[@"discovery error: ",[error description]]];
    88          } else {
    89              NSHTTPURLResponse *res = (NSHTTPURLResponse *)response;
    90  
    91              if (res.statusCode != 200) {
    92                  LALog(@"error with discovery: %@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
    93                  [LACamliUtil errorText:@[@"error discovery: ",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]]];
    94                  [LACamliUtil logText:@[[NSString stringWithFormat:@"server said: %@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]]]];
    95  
    96                  [[NSNotificationCenter defaultCenter] postNotificationName:CamliNotificationUploadEnd object:nil];
    97              } else {
    98                  NSError *err;
    99                  NSDictionary *config = [NSJSONSerialization JSONObjectWithData:data options:0 error:&err];
   100                  if (!err) {
   101                      self.blobRootComponent = config[@"blobRoot"];
   102                      [LACamliUtil logText:@[[NSString stringWithFormat:@"Welcome to %@'s camlistore",config[@"ownerName"]]]];
   103  
   104                      self.isAuthorized = YES;
   105                      [self.uploadQueue setSuspended:NO];
   106  
   107                      LALog(@"good discovery: %@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
   108                      [LACamliUtil statusText:@[@"discovery OK"]];
   109                  } else {
   110  
   111                      LALog(@"couldn't deserialize discovery json");
   112                      [LACamliUtil errorText:@[@"bad json from discovery", [err description]]];
   113                      [LACamliUtil logText:@[@"json from discovery: ",[err description]]];
   114                  }
   115              }
   116          }
   117      }];
   118  
   119      [data resume];
   120  }
   121  
   122  #pragma mark - upload methods
   123  
   124  - (BOOL)fileAlreadyUploaded:(LACamliFile *)file
   125  {
   126      NSParameterAssert(file);
   127  
   128      if ([self.uploadedBlobRefs containsObject:file.blobRef]) {
   129          return YES;
   130      }
   131  
   132      return NO;
   133  }
   134  
   135  // starts uploading immediately
   136  - (void)addFile:(LACamliFile *)file withCompletion:(void (^)())completion
   137  {
   138      NSParameterAssert(file);
   139  
   140      self.totalUploads++;
   141  
   142      if (![self isAuthorized]) {
   143          [self.uploadQueue setSuspended:YES];
   144  
   145          if (!self.authorizing) {
   146              [self discoveryWithUsername:self.username andPassword:self.password];
   147          }
   148      }
   149  
   150      LACamliUploadOperation *op = [[LACamliUploadOperation alloc] initWithFile:file andClient:self];
   151      __block LACamliUploadOperation *weakOp = op;
   152      op.completionBlock = ^{
   153          LALog(@"finished op %@",file.blobRef);
   154          if ([_delegate respondsToSelector:@selector(finishedUploadOperation:)]) {
   155              [_delegate performSelector:@selector(finishedUploadOperation:) onThread:[NSThread mainThread] withObject:weakOp waitUntilDone:NO];
   156          }
   157  
   158          if (weakOp.failedTransfer) {
   159              LALog(@"failed transfer");
   160          } else {
   161              [self.uploadedBlobRefs addObject:file.blobRef];
   162              [self.uploadedBlobRefs writeToFile:[self uploadedBlobRefArchivePath] atomically:YES];
   163          }
   164          weakOp = nil;
   165  
   166          if (![self.uploadQueue operationCount]) {
   167              self.totalUploads = 0;
   168          }
   169          if (completion) {
   170              completion();
   171          }
   172      };
   173  
   174      if ([_delegate respondsToSelector:@selector(addedUploadOperation:)]) {
   175          [_delegate performSelector:@selector(addedUploadOperation:) onThread:[NSThread mainThread] withObject:weakOp waitUntilDone:NO];
   176      }
   177  
   178      [self.uploadQueue addOperation:op];
   179  }
   180  
   181  #pragma mark - utility
   182  
   183  - (NSURL *)blobRoot
   184  {
   185      return [self.serverURL URLByAppendingPathComponent:self.blobRootComponent];
   186  }
   187  
   188  - (NSURL *)statUrl
   189  {
   190      return [[self blobRoot] URLByAppendingPathComponent:@"camli/stat"];
   191  }
   192  
   193  - (NSURL *)uploadUrl
   194  {
   195      return [[self blobRoot] URLByAppendingPathComponent:@"camli/upload"];
   196  }
   197  
   198  - (NSString *)encodedAuth
   199  {
   200      NSString *auth = [NSString stringWithFormat:@"%@:%@",self.username,self.password];
   201  
   202      return [LACamliUtil base64EncodedStringFromString:auth];
   203  }
   204  
   205  - (NSString *)uploadedBlobRefArchivePath
   206  {
   207      NSString *documents = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
   208      
   209      return [documents stringByAppendingPathComponent:@"uploadedRefs.plist"];
   210  }
   211  
   212  @end