1 ////////////////////////////////////////////////////////////////////////////
3 // Copyright 2016 Realm Inc.
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
9 // http://www.apache.org/licenses/LICENSE-2.0
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.
17 ////////////////////////////////////////////////////////////////////////////
19 #import "RLMSyncManager_Private.h"
21 #import "RLMRealmConfiguration+Sync.h"
22 #import "RLMSyncConfiguration_Private.hpp"
23 #import "RLMSyncSession_Private.hpp"
24 #import "RLMSyncUser_Private.hpp"
25 #import "RLMSyncUtil_Private.hpp"
28 #import "sync/sync_config.hpp"
29 #import "sync/sync_manager.hpp"
30 #import "sync/sync_session.hpp"
32 using namespace realm;
33 using Level = realm::util::Logger::Level;
37 Level levelForSyncLogLevel(RLMSyncLogLevel logLevel) {
39 case RLMSyncLogLevelOff: return Level::off;
40 case RLMSyncLogLevelFatal: return Level::fatal;
41 case RLMSyncLogLevelError: return Level::error;
42 case RLMSyncLogLevelWarn: return Level::warn;
43 case RLMSyncLogLevelInfo: return Level::info;
44 case RLMSyncLogLevelDetail: return Level::detail;
45 case RLMSyncLogLevelDebug: return Level::debug;
46 case RLMSyncLogLevelTrace: return Level::trace;
47 case RLMSyncLogLevelAll: return Level::all;
49 REALM_UNREACHABLE(); // Unrecognized log level.
52 RLMSyncLogLevel logLevelForLevel(Level logLevel) {
54 case Level::off: return RLMSyncLogLevelOff;
55 case Level::fatal: return RLMSyncLogLevelFatal;
56 case Level::error: return RLMSyncLogLevelError;
57 case Level::warn: return RLMSyncLogLevelWarn;
58 case Level::info: return RLMSyncLogLevelInfo;
59 case Level::detail: return RLMSyncLogLevelDetail;
60 case Level::debug: return RLMSyncLogLevelDebug;
61 case Level::trace: return RLMSyncLogLevelTrace;
62 case Level::all: return RLMSyncLogLevelAll;
64 REALM_UNREACHABLE(); // Unrecognized log level.
67 struct CocoaSyncLogger : public realm::util::RootLogger {
68 void do_log(Level, std::string message) override {
69 NSLog(@"Sync: %@", RLMStringDataToNSString(message));
73 struct CocoaSyncLoggerFactory : public realm::SyncLoggerFactory {
74 std::unique_ptr<realm::util::Logger> make_logger(realm::util::Logger::Level level) override {
75 auto logger = std::make_unique<CocoaSyncLogger>();
76 logger->set_level_threshold(level);
77 return std::move(logger);
79 } s_syncLoggerFactory;
81 } // anonymous namespace
83 @interface RLMSyncManager ()
84 - (instancetype)initWithCustomRootDirectory:(nullable NSURL *)rootDirectory NS_DESIGNATED_INITIALIZER;
87 @implementation RLMSyncManager
89 static RLMSyncManager *s_sharedManager = nil;
91 + (instancetype)sharedManager {
93 std::call_once(flag, [] {
95 s_sharedManager = [[RLMSyncManager alloc] initWithCustomRootDirectory:nil];
97 catch (std::exception const& e) {
98 @throw RLMException(e);
101 return s_sharedManager;
104 - (instancetype)initWithCustomRootDirectory:(NSURL *)rootDirectory {
105 if (self = [super init]) {
106 [RLMSyncUser _setUpBindingContextFactory];
108 // Initialize the sync engine.
109 SyncManager::shared().set_logger_factory(s_syncLoggerFactory);
110 bool should_encrypt = !getenv("REALM_DISABLE_METADATA_ENCRYPTION") && !RLMIsRunningInPlayground();
111 auto mode = should_encrypt ? SyncManager::MetadataMode::Encryption : SyncManager::MetadataMode::NoEncryption;
112 rootDirectory = rootDirectory ?: [NSURL fileURLWithPath:RLMDefaultDirectoryForBundleIdentifier(nil)];
113 SyncManager::shared().configure_file_system(rootDirectory.path.UTF8String, mode, none, true);
119 - (NSString *)appID {
121 _appID = [[NSBundle mainBundle] bundleIdentifier] ?: @"(none)";
126 #pragma mark - Passthrough properties
128 - (RLMSyncLogLevel)logLevel {
129 return logLevelForLevel(realm::SyncManager::shared().log_level());
132 - (void)setLogLevel:(RLMSyncLogLevel)logLevel {
133 realm::SyncManager::shared().set_log_level(levelForSyncLogLevel(logLevel));
136 #pragma mark - Private API
138 - (void)_fireError:(NSError *)error {
139 dispatch_async(dispatch_get_main_queue(), ^{
140 if (self.errorHandler) {
141 self.errorHandler(error, nil);
146 - (void)_fireErrorWithCode:(int)errorCode
147 message:(NSString *)message
149 session:(RLMSyncSession *)session
150 userInfo:(NSDictionary *)userInfo
151 errorClass:(RLMSyncSystemErrorKind)errorClass {
152 NSError *error = nil;
153 BOOL shouldMakeError = YES;
154 NSDictionary *custom = nil;
155 // Note that certain types of errors are 'interactive'; users have several options
156 // as to how to proceed after the error is reported.
157 switch (errorClass) {
158 case RLMSyncSystemErrorKindClientReset: {
159 std::string path = [userInfo[@(realm::SyncError::c_original_file_path_key)] UTF8String];
160 custom = @{kRLMSyncPathOfRealmBackupCopyKey:
161 userInfo[@(realm::SyncError::c_recovery_file_path_key)],
162 kRLMSyncErrorActionTokenKey:
163 [[RLMSyncErrorActionToken alloc] initWithOriginalPath:std::move(path)]
167 case RLMSyncSystemErrorKindPermissionDenied: {
168 std::string path = [userInfo[@(realm::SyncError::c_original_file_path_key)] UTF8String];
169 custom = @{kRLMSyncErrorActionTokenKey:
170 [[RLMSyncErrorActionToken alloc] initWithOriginalPath:std::move(path)]
174 case RLMSyncSystemErrorKindUser:
175 case RLMSyncSystemErrorKindSession:
177 case RLMSyncSystemErrorKindConnection:
178 case RLMSyncSystemErrorKindClient:
179 case RLMSyncSystemErrorKindUnknown:
180 // Report the error. There's nothing the user can do about it, though.
181 shouldMakeError = fatal;
184 error = shouldMakeError ? make_sync_error(errorClass, message, errorCode, custom) : nil;
185 dispatch_async(dispatch_get_main_queue(), ^{
186 if (!self.errorHandler || !error) {
189 self.errorHandler(error, session);
193 - (NSArray<RLMSyncUser *> *)_allUsers {
194 NSMutableArray<RLMSyncUser *> *buffer = [NSMutableArray array];
195 for (auto user : SyncManager::shared().all_logged_in_users()) {
196 [buffer addObject:[[RLMSyncUser alloc] initWithSyncUser:std::move(user)]];
201 + (void)resetForTesting {
202 SyncManager::shared().reset_for_testing();