auto_updater_mac.mm 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  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 "base/bind.h"
  10. #include "base/time/time.h"
  11. #include "base/strings/sys_string_conversions.h"
  12. namespace auto_updater {
  13. namespace {
  14. // The gloal SQRLUpdater object.
  15. SQRLUpdater* g_updater = nil;
  16. } // namespace
  17. namespace {
  18. bool g_update_available = false;
  19. std::string update_url_ = "";
  20. } // namespace
  21. std::string AutoUpdater::GetFeedURL() {
  22. return update_url_;
  23. }
  24. // static
  25. void AutoUpdater::SetFeedURL(const std::string& feed,
  26. const HeaderMap& requestHeaders) {
  27. Delegate* delegate = GetDelegate();
  28. if (!delegate)
  29. return;
  30. update_url_ = feed;
  31. NSURL* url = [NSURL URLWithString:base::SysUTF8ToNSString(feed)];
  32. NSMutableURLRequest* urlRequest = [NSMutableURLRequest requestWithURL:url];
  33. for (const auto& it : requestHeaders) {
  34. [urlRequest setValue:base::SysUTF8ToNSString(it.second)
  35. forHTTPHeaderField:base::SysUTF8ToNSString(it.first)];
  36. }
  37. if (g_updater)
  38. [g_updater release];
  39. // Initialize the SQRLUpdater.
  40. @try {
  41. g_updater = [[SQRLUpdater alloc] initWithUpdateRequest:urlRequest];
  42. } @catch (NSException* error) {
  43. delegate->OnError(base::SysNSStringToUTF8(error.reason));
  44. return;
  45. }
  46. [[g_updater rac_valuesForKeyPath:@"state" observer:g_updater]
  47. subscribeNext:^(NSNumber *stateNumber) {
  48. int state = [stateNumber integerValue];
  49. // Dispatching the event on main thread.
  50. dispatch_async(dispatch_get_main_queue(), ^{
  51. if (state == SQRLUpdaterStateCheckingForUpdate)
  52. delegate->OnCheckingForUpdate();
  53. else if (state == SQRLUpdaterStateDownloadingUpdate)
  54. delegate->OnUpdateAvailable();
  55. });
  56. }];
  57. }
  58. // static
  59. void AutoUpdater::CheckForUpdates() {
  60. Delegate* delegate = GetDelegate();
  61. if (!delegate)
  62. return;
  63. [[[[g_updater.checkForUpdatesCommand
  64. execute:nil]
  65. // Send a `nil` after everything...
  66. concat:[RACSignal return:nil]]
  67. // But only take the first value. If an update is sent, we'll get that.
  68. // Otherwise, we'll get our inserted `nil` value.
  69. take:1]
  70. subscribeNext:^(SQRLDownloadedUpdate *downloadedUpdate) {
  71. if (downloadedUpdate) {
  72. g_update_available = true;
  73. SQRLUpdate* update = downloadedUpdate.update;
  74. // There is a new update that has been downloaded.
  75. delegate->OnUpdateDownloaded(
  76. base::SysNSStringToUTF8(update.releaseNotes),
  77. base::SysNSStringToUTF8(update.releaseName),
  78. base::Time::FromDoubleT(update.releaseDate.timeIntervalSince1970),
  79. base::SysNSStringToUTF8(update.updateURL.absoluteString));
  80. } else {
  81. g_update_available = false;
  82. // When the completed event is sent with no update, then we know there
  83. // is no update available.
  84. delegate->OnUpdateNotAvailable();
  85. }
  86. } error:^(NSError *error) {
  87. NSMutableString* failureString =
  88. [NSMutableString stringWithString:error.localizedDescription];
  89. if (error.localizedFailureReason) {
  90. [failureString appendString:@": "];
  91. [failureString appendString:error.localizedFailureReason];
  92. }
  93. if (error.localizedRecoverySuggestion) {
  94. if (![failureString hasSuffix:@"."])
  95. [failureString appendString:@"."];
  96. [failureString appendString:@" "];
  97. [failureString appendString:error.localizedRecoverySuggestion];
  98. }
  99. delegate->OnError(base::SysNSStringToUTF8(failureString));
  100. }];
  101. }
  102. void AutoUpdater::QuitAndInstall() {
  103. Delegate* delegate = AutoUpdater::GetDelegate();
  104. if (g_update_available) {
  105. [[g_updater relaunchToInstallUpdate] subscribeError:^(NSError* error) {
  106. if (delegate)
  107. delegate->OnError(base::SysNSStringToUTF8(error.localizedDescription));
  108. }];
  109. } else {
  110. if (delegate)
  111. delegate->OnError("No update available, can't quit and install");
  112. }
  113. }
  114. } // namespace auto_updater