/core/externals/update-engine/Core/KSUpdateCheckAction.m

http://macfuse.googlecode.com/ · Objective C · 199 lines · 143 code · 31 blank · 25 comment · 17 complexity · 5869de022b1426a1406456a2dda96fc7 MD5 · raw file

  1. // Copyright 2008 Google Inc.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #import "KSUpdateCheckAction.h"
  15. #import "GDataHTTPFetcher.h"
  16. #import "KSActionConstants.h"
  17. #import "KSActionPipe.h"
  18. #import "KSActionProcessor.h"
  19. #import "KSFetcherFactory.h"
  20. #import "KSServer.h"
  21. #import "KSTicket.h"
  22. #import "KSUpdateAction.h"
  23. @interface KSUpdateCheckAction (FetcherCallbacks)
  24. // A KSUpdateCheckAction may ask for information via GDataHTTPFetcher
  25. // which is async. These are callbacks passed to [GDataHTTPFetcher
  26. // beginFetchingWithDelegate::::] to let us know what happened.
  27. - (void)fetcher:(GDataHTTPFetcher *)fetcher finishedWithData:(NSData *)data;
  28. - (void)fetcher:(GDataHTTPFetcher *)fetcher failedWithError:(NSError *)error;
  29. @end
  30. @implementation KSUpdateCheckAction
  31. + (id)checkerWithServer:(KSServer *)server tickets:(NSArray *)tickets {
  32. return [[[KSUpdateCheckAction alloc] initWithServer:server
  33. tickets:tickets] autorelease];
  34. }
  35. - (id)init {
  36. return [self initWithServer:nil tickets:nil];
  37. }
  38. - (id)initWithServer:(KSServer *)server tickets:(NSArray *)tickets {
  39. return [self initWithFetcherFactory:[KSFetcherFactory factory]
  40. server:server
  41. tickets:tickets];
  42. }
  43. - (id)initWithFetcherFactory:(KSFetcherFactory *)fetcherFactory
  44. server:(KSServer *)server
  45. tickets:(NSArray *)tickets {
  46. if ((self = [super init])) {
  47. if ((fetcherFactory == nil) ||
  48. (server == nil) ||
  49. ([tickets count] == 0)) {
  50. [self release];
  51. return nil;
  52. }
  53. // check invariant; make sure all tickets point to the same server URL
  54. if ([tickets count] > 1) {
  55. KSTicket *first = [tickets objectAtIndex:0];
  56. NSEnumerator *tenum = [tickets objectEnumerator];
  57. KSTicket *t = nil;
  58. while ((t = [tenum nextObject])) {
  59. if (![[first serverURL] isEqual:[t serverURL]]) {
  60. GTMLoggerInfo(@"UpdateChecker passed tickets with different URLs?");
  61. [self release];
  62. return nil;
  63. }
  64. }
  65. }
  66. fetcherFactory_ = [fetcherFactory retain];
  67. server_ = [server retain];
  68. tickets_ = [tickets copy];
  69. fetchers_ = [[NSMutableArray alloc] init];
  70. allSuccessful_ = YES; // so far...
  71. }
  72. return self;
  73. }
  74. - (void)dealloc {
  75. [fetcherFactory_ release];
  76. [server_ release];
  77. [tickets_ release];
  78. [fetchers_ release];
  79. [super dealloc];
  80. }
  81. // Override of -[KSAction performAction] to define ourselves as an
  82. // action object. Like KSAction, we are called from our owning
  83. // KSActionProcessor. This method happens to be async.
  84. - (void)performAction {
  85. NSArray *requests = [server_ requestsForTickets:tickets_];
  86. // Try and make debugging easier
  87. NSEnumerator *renum = [requests objectEnumerator];
  88. NSURLRequest *req = nil;
  89. #ifdef DEBUG
  90. int x = 0;
  91. while ((req = [renum nextObject])) {
  92. NSData *data = [req HTTPBody];
  93. // %.*s since we need length (data not NULL-terminated)
  94. GTMLoggerDebug(@"** XML request %d:\n%.*s", x++,
  95. [data length], (char*)[data bytes]);
  96. }
  97. #endif
  98. renum = [requests objectEnumerator];
  99. while ((req = [renum nextObject])) {
  100. GDataHTTPFetcher *fetcher = [fetcherFactory_ createFetcherForRequest:req];
  101. _GTMDevAssert(fetcher, @"no fetcher");
  102. [fetchers_ addObject:fetcher];
  103. [fetcher beginFetchWithDelegate:self
  104. didFinishSelector:@selector(fetcher:finishedWithData:)
  105. didFailSelector:@selector(fetcher:failedWithError:)];
  106. }
  107. }
  108. - (void)terminateAction {
  109. NSEnumerator *fenum = [fetchers_ objectEnumerator];
  110. GDataHTTPFetcher *fetcher = nil;
  111. while ((fetcher = [fenum nextObject])) {
  112. if ([fetcher isFetching]) {
  113. [fetcher stopFetching];
  114. }
  115. }
  116. [fetchers_ removeAllObjects];
  117. }
  118. - (void)requestFinishedForFetcher:(GDataHTTPFetcher *)fetcher success:(BOOL)successful {
  119. [fetchers_ removeObject:fetcher];
  120. if (successful == NO)
  121. allSuccessful_ = NO;
  122. if ([fetchers_ count] == 0) {
  123. [[self processor] finishedProcessing:self successfully:allSuccessful_];
  124. }
  125. }
  126. - (int)outstandingRequests {
  127. return [fetchers_ count];
  128. }
  129. - (id)delegate {
  130. return delegate_;
  131. }
  132. - (void)setDelegate:(id)delegate {
  133. delegate_ = delegate;
  134. }
  135. - (NSString *)description {
  136. return [NSString stringWithFormat:@"<%@:%p server=%@ tickets=%@>",
  137. [self class], self, server_, tickets_];
  138. }
  139. @end // KSUpdateCheckAction
  140. @implementation KSUpdateCheckAction (FetcherCallbacks)
  141. - (void)fetcher:(GDataHTTPFetcher *)fetcher finishedWithData:(NSData *)data {
  142. NSURLResponse *response = [fetcher response];
  143. NSString *prettyData = [server_ prettyPrintResponse:response data:data];
  144. GTMLoggerDebug(@"** XML response:\n%@", prettyData);
  145. NSDictionary *oob;
  146. NSArray *updateInfos = [server_ updateInfosForResponse:response
  147. data:data
  148. outOfBandData:&oob];
  149. KSTicket *first = [tickets_ objectAtIndex:0];
  150. // If |oob| is nil for this dictionary creation, life is still good.
  151. // The outgoing dictionary just won't have an out-of-band data
  152. // element.
  153. NSDictionary *results =
  154. [NSDictionary dictionaryWithObjectsAndKeys:
  155. [first serverURL], KSActionServerURLKey,
  156. updateInfos, KSActionUpdateInfosKey,
  157. oob, KSActionOutOfBandDataKey,
  158. nil];
  159. [[self outPipe] setContents:results];
  160. [self requestFinishedForFetcher:fetcher success:YES];
  161. }
  162. - (void)fetcher:(GDataHTTPFetcher *)fetcher failedWithError:(NSError *)error {
  163. GTMLoggerError(@"KSUpdateCheckAction failed with error %@", error);
  164. if ([[self delegate] respondsToSelector:@selector(fetcher:failedWithError:)])
  165. [[self delegate] fetcher:fetcher failedWithError:error];
  166. [self requestFinishedForFetcher:fetcher success:NO];
  167. }
  168. @end