auto_updater_mac.mm 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. // Copyright (c) 2013 GitHub, Inc.
  2. // Use of this source code is governed by the MIT license that can be
  3. // found in the LICENSE file.
  4. #include "atom/browser/auto_updater.h"
  5. #import <ReactiveCocoa/RACCommand.h>
  6. #import <ReactiveCocoa/RACSignal.h>
  7. #import <ReactiveCocoa/NSObject+RACPropertySubscribing.h>
  8. #import <Squirrel/Squirrel.h>
  9. #include "atom/browser/browser.h"
  10. #include "atom/common/native_mate_converters/value_converter.h"
  11. #include "base/bind.h"
  12. #include "base/time/time.h"
  13. #include "base/strings/sys_string_conversions.h"
  14. #include "native_mate/converter.h"
  15. #include "native_mate/dictionary.h"
  16. namespace auto_updater {
  17. namespace {
  18. // The gloal SQRLUpdater object.
  19. SQRLUpdater* g_updater = nil;
  20. } // namespace
  21. namespace {
  22. bool g_update_available = false;
  23. std::string update_url_ = "";
  24. } // namespace
  25. std::string AutoUpdater::GetFeedURL() {
  26. return update_url_;
  27. }
  28. // static
  29. void AutoUpdater::SetFeedURL(mate::Arguments* args) {
  30. mate::Dictionary opts;
  31. std::string feed;
  32. HeaderMap requestHeaders;
  33. std::string serverType = "default";
  34. if (args->GetNext(&opts)) {
  35. if (!opts.Get("url", &feed)) {
  36. args->ThrowError("Expected options object to contain a 'url' string property in setFeedUrl call");
  37. return;
  38. }
  39. opts.Get("headers", &requestHeaders);
  40. opts.Get("serverType", &serverType);
  41. if (serverType != "default" && serverType != "json") {
  42. args->ThrowError("Expected serverType to be 'default' or 'json'");
  43. return;
  44. }
  45. } else if (args->GetNext(&feed)) {
  46. args->GetNext(&requestHeaders);
  47. } else {
  48. args->ThrowError("Expected an options object with a 'url' property to be provided");
  49. return;
  50. }
  51. Delegate* delegate = GetDelegate();
  52. if (!delegate)
  53. return;
  54. update_url_ = feed;
  55. NSURL* url = [NSURL URLWithString:base::SysUTF8ToNSString(feed)];
  56. NSMutableURLRequest* urlRequest = [NSMutableURLRequest requestWithURL:url];
  57. for (const auto& it : requestHeaders) {
  58. [urlRequest setValue:base::SysUTF8ToNSString(it.second)
  59. forHTTPHeaderField:base::SysUTF8ToNSString(it.first)];
  60. }
  61. if (g_updater)
  62. [g_updater release];
  63. // Initialize the SQRLUpdater.
  64. @try {
  65. if (serverType == "json") {
  66. NSString* nsAppVersion = base::SysUTF8ToNSString(atom::Browser::Get()->GetVersion());
  67. g_updater = [[SQRLUpdater alloc] initWithUpdateRequest:urlRequest forVersion:nsAppVersion];
  68. } else {
  69. // default
  70. g_updater = [[SQRLUpdater alloc] initWithUpdateRequest:urlRequest];
  71. }
  72. } @catch (NSException* error) {
  73. delegate->OnError(base::SysNSStringToUTF8(error.reason));
  74. return;
  75. }
  76. [[g_updater rac_valuesForKeyPath:@"state" observer:g_updater]
  77. subscribeNext:^(NSNumber *stateNumber) {
  78. int state = [stateNumber integerValue];
  79. // Dispatching the event on main thread.
  80. dispatch_async(dispatch_get_main_queue(), ^{
  81. if (state == SQRLUpdaterStateCheckingForUpdate)
  82. delegate->OnCheckingForUpdate();
  83. else if (state == SQRLUpdaterStateDownloadingUpdate)
  84. delegate->OnUpdateAvailable();
  85. });
  86. }];
  87. }
  88. // static
  89. void AutoUpdater::CheckForUpdates() {
  90. Delegate* delegate = GetDelegate();
  91. if (!delegate)
  92. return;
  93. [[[[g_updater.checkForUpdatesCommand
  94. execute:nil]
  95. // Send a `nil` after everything...
  96. concat:[RACSignal return:nil]]
  97. // But only take the first value. If an update is sent, we'll get that.
  98. // Otherwise, we'll get our inserted `nil` value.
  99. take:1]
  100. subscribeNext:^(SQRLDownloadedUpdate *downloadedUpdate) {
  101. if (downloadedUpdate) {
  102. g_update_available = true;
  103. SQRLUpdate* update = downloadedUpdate.update;
  104. // There is a new update that has been downloaded.
  105. delegate->OnUpdateDownloaded(
  106. base::SysNSStringToUTF8(update.releaseNotes),
  107. base::SysNSStringToUTF8(update.releaseName),
  108. base::Time::FromDoubleT(update.releaseDate.timeIntervalSince1970),
  109. base::SysNSStringToUTF8(update.updateURL.absoluteString));
  110. } else {
  111. g_update_available = false;
  112. // When the completed event is sent with no update, then we know there
  113. // is no update available.
  114. delegate->OnUpdateNotAvailable();
  115. }
  116. } error:^(NSError *error) {
  117. NSMutableString *failureString =
  118. [NSMutableString stringWithString:error.localizedDescription];
  119. if (error.localizedFailureReason) {
  120. [failureString appendString:@": "];
  121. [failureString appendString:error.localizedFailureReason];
  122. }
  123. if (error.localizedRecoverySuggestion) {
  124. if (![failureString hasSuffix:@"."])
  125. [failureString appendString:@"."];
  126. [failureString appendString:@" "];
  127. [failureString appendString:error.localizedRecoverySuggestion];
  128. }
  129. delegate->OnError(base::SysNSStringToUTF8(failureString), error.code,
  130. base::SysNSStringToUTF8(error.domain));
  131. }];
  132. }
  133. void AutoUpdater::QuitAndInstall() {
  134. Delegate* delegate = AutoUpdater::GetDelegate();
  135. if (g_update_available) {
  136. [[g_updater relaunchToInstallUpdate] subscribeError:^(NSError* error) {
  137. if (delegate)
  138. delegate->OnError(base::SysNSStringToUTF8(error.localizedDescription),
  139. error.code, base::SysNSStringToUTF8(error.domain));
  140. }];
  141. } else {
  142. if (delegate)
  143. delegate->OnError("No update available, can't quit and install");
  144. }
  145. }
  146. } // namespace auto_updater