added iOS source code
[wl-app.git] / iOS / Pods / Realm / Realm / RLMSyncManager.mm
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
19 #import "RLMSyncManager_Private.h"
20
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"
26 #import "RLMUtil.hpp"
27
28 #import "sync/sync_config.hpp"
29 #import "sync/sync_manager.hpp"
30 #import "sync/sync_session.hpp"
31
32 using namespace realm;
33 using Level = realm::util::Logger::Level;
34
35 namespace {
36
37 Level levelForSyncLogLevel(RLMSyncLogLevel logLevel) {
38     switch (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;
48     }
49     REALM_UNREACHABLE();    // Unrecognized log level.
50 }
51
52 RLMSyncLogLevel logLevelForLevel(Level logLevel) {
53     switch (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;
63     }
64     REALM_UNREACHABLE();    // Unrecognized log level.
65 }
66
67 struct CocoaSyncLogger : public realm::util::RootLogger {
68     void do_log(Level, std::string message) override {
69         NSLog(@"Sync: %@", RLMStringDataToNSString(message));
70     }
71 };
72
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);
78     }
79 } s_syncLoggerFactory;
80
81 } // anonymous namespace
82
83 @interface RLMSyncManager ()
84 - (instancetype)initWithCustomRootDirectory:(nullable NSURL *)rootDirectory NS_DESIGNATED_INITIALIZER;
85 @end
86
87 @implementation RLMSyncManager
88
89 static RLMSyncManager *s_sharedManager = nil;
90
91 + (instancetype)sharedManager {
92     std::once_flag flag;
93     std::call_once(flag, [] {
94         try {
95             s_sharedManager = [[RLMSyncManager alloc] initWithCustomRootDirectory:nil];
96         }
97         catch (std::exception const& e) {
98             @throw RLMException(e);
99         }
100     });
101     return s_sharedManager;
102 }
103
104 - (instancetype)initWithCustomRootDirectory:(NSURL *)rootDirectory {
105     if (self = [super init]) {
106         [RLMSyncUser _setUpBindingContextFactory];
107
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);
114         return self;
115     }
116     return nil;
117 }
118
119 - (NSString *)appID {
120     if (!_appID) {
121         _appID = [[NSBundle mainBundle] bundleIdentifier] ?: @"(none)";
122     }
123     return _appID;
124 }
125
126 #pragma mark - Passthrough properties
127
128 - (RLMSyncLogLevel)logLevel {
129     return logLevelForLevel(realm::SyncManager::shared().log_level());
130 }
131
132 - (void)setLogLevel:(RLMSyncLogLevel)logLevel {
133     realm::SyncManager::shared().set_log_level(levelForSyncLogLevel(logLevel));
134 }
135
136 #pragma mark - Private API
137
138 - (void)_fireError:(NSError *)error {
139     dispatch_async(dispatch_get_main_queue(), ^{
140         if (self.errorHandler) {
141             self.errorHandler(error, nil);
142         }
143     });
144 }
145
146 - (void)_fireErrorWithCode:(int)errorCode
147                    message:(NSString *)message
148                    isFatal:(BOOL)fatal
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)]
164                        };;
165             break;
166         }
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)]
171                        };
172             break;
173         }
174         case RLMSyncSystemErrorKindUser:
175         case RLMSyncSystemErrorKindSession:
176             break;
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;
182             break;
183     }
184     error = shouldMakeError ? make_sync_error(errorClass, message, errorCode, custom) : nil;
185     dispatch_async(dispatch_get_main_queue(), ^{
186         if (!self.errorHandler || !error) {
187             return;
188         }
189         self.errorHandler(error, session);
190     });
191 }
192
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)]];
197     }
198     return buffer;
199 }
200
201 + (void)resetForTesting {
202     SyncManager::shared().reset_for_testing();
203 }
204
205 @end