RLMSyncManager.mm 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. ////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright 2016 Realm Inc.
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License");
  6. // you may not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. //
  17. ////////////////////////////////////////////////////////////////////////////
  18. #import "RLMSyncManager_Private.h"
  19. #import "RLMRealmConfiguration+Sync.h"
  20. #import "RLMSyncConfiguration_Private.hpp"
  21. #import "RLMSyncSession_Private.hpp"
  22. #import "RLMSyncUser_Private.hpp"
  23. #import "RLMSyncUtil_Private.hpp"
  24. #import "RLMUtil.hpp"
  25. #import "sync/sync_config.hpp"
  26. #import "sync/sync_manager.hpp"
  27. #import "sync/sync_session.hpp"
  28. #if !defined(REALM_COCOA_VERSION)
  29. #import "RLMVersion.h"
  30. #endif
  31. using namespace realm;
  32. using Level = realm::util::Logger::Level;
  33. namespace {
  34. Level levelForSyncLogLevel(RLMSyncLogLevel logLevel) {
  35. switch (logLevel) {
  36. case RLMSyncLogLevelOff: return Level::off;
  37. case RLMSyncLogLevelFatal: return Level::fatal;
  38. case RLMSyncLogLevelError: return Level::error;
  39. case RLMSyncLogLevelWarn: return Level::warn;
  40. case RLMSyncLogLevelInfo: return Level::info;
  41. case RLMSyncLogLevelDetail: return Level::detail;
  42. case RLMSyncLogLevelDebug: return Level::debug;
  43. case RLMSyncLogLevelTrace: return Level::trace;
  44. case RLMSyncLogLevelAll: return Level::all;
  45. }
  46. REALM_UNREACHABLE(); // Unrecognized log level.
  47. }
  48. RLMSyncLogLevel logLevelForLevel(Level logLevel) {
  49. switch (logLevel) {
  50. case Level::off: return RLMSyncLogLevelOff;
  51. case Level::fatal: return RLMSyncLogLevelFatal;
  52. case Level::error: return RLMSyncLogLevelError;
  53. case Level::warn: return RLMSyncLogLevelWarn;
  54. case Level::info: return RLMSyncLogLevelInfo;
  55. case Level::detail: return RLMSyncLogLevelDetail;
  56. case Level::debug: return RLMSyncLogLevelDebug;
  57. case Level::trace: return RLMSyncLogLevelTrace;
  58. case Level::all: return RLMSyncLogLevelAll;
  59. }
  60. REALM_UNREACHABLE(); // Unrecognized log level.
  61. }
  62. #pragma mark - Loggers
  63. struct CocoaSyncLogger : public realm::util::RootLogger {
  64. void do_log(Level, std::string message) override {
  65. NSLog(@"Sync: %@", RLMStringDataToNSString(message));
  66. }
  67. };
  68. struct CocoaSyncLoggerFactory : public realm::SyncLoggerFactory {
  69. std::unique_ptr<realm::util::Logger> make_logger(realm::util::Logger::Level level) override {
  70. auto logger = std::make_unique<CocoaSyncLogger>();
  71. logger->set_level_threshold(level);
  72. return std::move(logger);
  73. }
  74. } s_syncLoggerFactory;
  75. struct CallbackLogger : public realm::util::RootLogger {
  76. RLMSyncLogFunction logFn;
  77. void do_log(Level level, std::string message) override {
  78. @autoreleasepool {
  79. logFn(logLevelForLevel(level), RLMStringDataToNSString(message));
  80. }
  81. }
  82. };
  83. struct CallbackLoggerFactory : public realm::SyncLoggerFactory {
  84. RLMSyncLogFunction logFn;
  85. std::unique_ptr<realm::util::Logger> make_logger(realm::util::Logger::Level level) override {
  86. auto logger = std::make_unique<CallbackLogger>();
  87. logger->logFn = logFn;
  88. logger->set_level_threshold(level);
  89. return std::move(logger); // not a redundant move because it's a different type
  90. }
  91. CallbackLoggerFactory(RLMSyncLogFunction logFn) : logFn(logFn) { }
  92. };
  93. } // anonymous namespace
  94. #pragma mark - RLMSyncManager
  95. @interface RLMSyncTimeoutOptions () {
  96. @public
  97. realm::SyncClientTimeouts _options;
  98. }
  99. @end
  100. @implementation RLMSyncManager {
  101. std::unique_ptr<CallbackLoggerFactory> _loggerFactory;
  102. }
  103. static RLMSyncManager *s_sharedManager = nil;
  104. - (instancetype)initPrivate {
  105. return self = [super init];
  106. }
  107. + (instancetype)sharedManager {
  108. static std::once_flag flag;
  109. std::call_once(flag, [] {
  110. try {
  111. [RLMSyncUser _setUpBindingContextFactory];
  112. s_sharedManager = [[RLMSyncManager alloc] initPrivate];
  113. [s_sharedManager configureWithRootDirectory:nil];
  114. }
  115. catch (std::exception const& e) {
  116. @throw RLMException(e);
  117. }
  118. });
  119. return s_sharedManager;
  120. }
  121. - (void)configureWithRootDirectory:(NSURL *)rootDirectory {
  122. SyncClientConfig config;
  123. bool should_encrypt = !getenv("REALM_DISABLE_METADATA_ENCRYPTION") && !RLMIsRunningInPlayground();
  124. config.logger_factory = &s_syncLoggerFactory;
  125. config.metadata_mode = should_encrypt ? SyncManager::MetadataMode::Encryption
  126. : SyncManager::MetadataMode::NoEncryption;
  127. @autoreleasepool {
  128. rootDirectory = rootDirectory ?: [NSURL fileURLWithPath:RLMDefaultDirectoryForBundleIdentifier(nil)];
  129. config.base_file_path = rootDirectory.path.UTF8String;
  130. bool isSwift = !!NSClassFromString(@"RealmSwiftObjectUtil");
  131. config.user_agent_binding_info =
  132. util::format("Realm%1/%2", isSwift ? "Swift" : "ObjectiveC",
  133. RLMStringDataWithNSString(REALM_COCOA_VERSION));
  134. config.user_agent_application_info = RLMStringDataWithNSString(self.appID);
  135. }
  136. SyncManager::shared().configure(config);
  137. }
  138. - (NSString *)appID {
  139. if (!_appID) {
  140. _appID = [[NSBundle mainBundle] bundleIdentifier] ?: @"(none)";
  141. }
  142. return _appID;
  143. }
  144. - (void)setUserAgent:(NSString *)userAgent {
  145. SyncManager::shared().set_user_agent(RLMStringDataWithNSString(userAgent));
  146. _userAgent = userAgent;
  147. }
  148. - (void)setCustomRequestHeaders:(NSDictionary<NSString *,NSString *> *)customRequestHeaders {
  149. _customRequestHeaders = customRequestHeaders.copy;
  150. for (auto&& user : SyncManager::shared().all_logged_in_users()) {
  151. for (auto&& session : user->all_sessions()) {
  152. auto config = session->config();
  153. config.custom_http_headers.clear();;
  154. for (NSString *key in customRequestHeaders) {
  155. config.custom_http_headers.emplace(key.UTF8String, customRequestHeaders[key].UTF8String);
  156. }
  157. session->update_configuration(std::move(config));
  158. }
  159. }
  160. }
  161. - (void)setLogger:(RLMSyncLogFunction)logFn {
  162. _logger = logFn;
  163. if (_logger) {
  164. _loggerFactory = std::make_unique<CallbackLoggerFactory>(logFn);
  165. SyncManager::shared().set_logger_factory(*_loggerFactory);
  166. }
  167. else {
  168. _loggerFactory = nullptr;
  169. SyncManager::shared().set_logger_factory(s_syncLoggerFactory);
  170. }
  171. }
  172. - (void)setTimeoutOptions:(RLMSyncTimeoutOptions *)timeoutOptions {
  173. _timeoutOptions = timeoutOptions;
  174. SyncManager::shared().set_timeouts(timeoutOptions->_options);
  175. }
  176. #pragma mark - Passthrough properties
  177. - (RLMSyncLogLevel)logLevel {
  178. return logLevelForLevel(realm::SyncManager::shared().log_level());
  179. }
  180. - (void)setLogLevel:(RLMSyncLogLevel)logLevel {
  181. realm::SyncManager::shared().set_log_level(levelForSyncLogLevel(logLevel));
  182. }
  183. #pragma mark - Private API
  184. - (void)_fireError:(NSError *)error {
  185. dispatch_async(dispatch_get_main_queue(), ^{
  186. if (self.errorHandler) {
  187. self.errorHandler(error, nil);
  188. }
  189. });
  190. }
  191. - (NSArray<RLMSyncUser *> *)_allUsers {
  192. NSMutableArray<RLMSyncUser *> *buffer = [NSMutableArray array];
  193. for (auto user : SyncManager::shared().all_logged_in_users()) {
  194. [buffer addObject:[[RLMSyncUser alloc] initWithSyncUser:std::move(user)]];
  195. }
  196. return buffer;
  197. }
  198. + (void)resetForTesting {
  199. RLMSyncManager *manager = self.sharedManager;
  200. manager->_errorHandler = nil;
  201. manager->_appID = nil;
  202. manager->_userAgent = nil;
  203. manager->_logger = nil;
  204. manager->_authorizationHeaderName = nil;
  205. manager->_customRequestHeaders = nil;
  206. manager->_pinnedCertificatePaths = nil;
  207. manager->_timeoutOptions = nil;
  208. SyncManager::shared().reset_for_testing();
  209. }
  210. - (RLMNetworkRequestOptions *)networkRequestOptions {
  211. RLMNetworkRequestOptions *options = [[RLMNetworkRequestOptions alloc] init];
  212. options.authorizationHeaderName = self.authorizationHeaderName;
  213. options.customHeaders = self.customRequestHeaders;
  214. options.pinnedCertificatePaths = self.pinnedCertificatePaths;
  215. return options;
  216. }
  217. @end
  218. #pragma mark - RLMSyncTimeoutOptions
  219. @implementation RLMSyncTimeoutOptions
  220. - (NSUInteger)connectTimeout {
  221. return _options.connect_timeout;
  222. }
  223. - (void)setConnectTimeout:(NSUInteger)connectTimeout {
  224. _options.connect_timeout = connectTimeout;
  225. }
  226. - (NSUInteger)connectLingerTime {
  227. return _options.connection_linger_time;
  228. }
  229. - (void)setConnectionLingerTime:(NSUInteger)connectionLingerTime {
  230. _options.connection_linger_time = connectionLingerTime;
  231. }
  232. - (NSUInteger)pingKeepalivePeriod {
  233. return _options.ping_keepalive_period;
  234. }
  235. - (void)setPingKeepalivePeriod:(NSUInteger)pingKeepalivePeriod {
  236. _options.ping_keepalive_period = pingKeepalivePeriod;
  237. }
  238. - (NSUInteger)pongKeepaliveTimeout {
  239. return _options.pong_keepalive_timeout;
  240. }
  241. - (void)setPongKeepaliveTimeout:(NSUInteger)pongKeepaliveTimeout {
  242. _options.pong_keepalive_timeout = pongKeepaliveTimeout;
  243. }
  244. - (NSUInteger)fastReconnectLimit {
  245. return _options.fast_reconnect_limit;
  246. }
  247. - (void)setFastReconnectLimit:(NSUInteger)fastReconnectLimit {
  248. _options.fast_reconnect_limit = fastReconnectLimit;
  249. }
  250. @end