auto_updater_mac.mm 5.6 KB

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