added iOS source code
[wl-app.git] / iOS / Pods / Realm / Realm / RLMSyncSession.mm
diff --git a/iOS/Pods/Realm/Realm/RLMSyncSession.mm b/iOS/Pods/Realm/Realm/RLMSyncSession.mm
new file mode 100644 (file)
index 0000000..e00af7f
--- /dev/null
@@ -0,0 +1,221 @@
+////////////////////////////////////////////////////////////////////////////
+//
+// Copyright 2016 Realm Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////
+
+#import "RLMSyncSession_Private.hpp"
+
+#import "RLMSyncConfiguration_Private.hpp"
+#import "RLMSyncUser_Private.hpp"
+#import "RLMSyncUtil_Private.hpp"
+#import "sync/sync_session.hpp"
+
+using namespace realm;
+
+@interface RLMSyncErrorActionToken () {
+@public
+    std::string _originalPath;
+    BOOL _isValid;
+}
+@end
+
+@interface RLMProgressNotificationToken() {
+    uint64_t _token;
+    std::weak_ptr<SyncSession> _session;
+}
+@end
+
+@implementation RLMProgressNotificationToken
+
+- (void)suppressNextNotification {
+    // No-op, but implemented in case this token is passed to
+    // `-[RLMRealm commitWriteTransactionWithoutNotifying:]`.
+}
+
+- (void)invalidate {
+    if (auto session = _session.lock()) {
+        session->unregister_progress_notifier(_token);
+        _session.reset();
+        _token = 0;
+    }
+}
+
+- (void)dealloc {
+    if (_token != 0) {
+        NSLog(@"RLMProgressNotificationToken released without unregistering a notification. "
+              @"You must hold on to the RLMProgressNotificationToken and call "
+              @"-[RLMProgressNotificationToken invalidate] when you no longer wish to receive "
+              @"progress update notifications.");
+    }
+}
+
+- (nullable instancetype)initWithTokenValue:(uint64_t)token
+                                    session:(std::shared_ptr<SyncSession>)session {
+    if (token == 0) {
+        return nil;
+    }
+    if (self = [super init]) {
+        _token = token;
+        _session = session;
+        return self;
+    }
+    return nil;
+}
+
+@end
+
+@interface RLMSyncSession ()
+@property (class, nonatomic, readonly) dispatch_queue_t notificationsQueue;
+@end
+
+@implementation RLMSyncSession
+
++ (dispatch_queue_t)notificationsQueue {
+    static dispatch_queue_t queue;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        queue = dispatch_queue_create("io.realm.sync.sessionsNotificationQueue", DISPATCH_QUEUE_SERIAL);
+    });
+    return queue;
+}
+
+- (instancetype)initWithSyncSession:(std::shared_ptr<SyncSession>)session {
+    if (self = [super init]) {
+        _session = session;
+        return self;
+    }
+    return nil;
+}
+
+- (RLMSyncConfiguration *)configuration {
+    if (auto session = _session.lock()) {
+        if (session->state() != SyncSession::PublicState::Error) {
+            return [[RLMSyncConfiguration alloc] initWithRawConfig:session->config()];
+        }
+    }
+    return nil;
+}
+
+- (NSURL *)realmURL {
+    if (auto session = _session.lock()) {
+        if (auto url = session->full_realm_url()) {
+            return [NSURL URLWithString:@(url->c_str())];
+        }
+    }
+    return nil;
+}
+
+- (RLMSyncUser *)parentUser {
+    if (auto session = _session.lock()) {
+        if (session->state() != SyncSession::PublicState::Error) {
+            return [[RLMSyncUser alloc] initWithSyncUser:session->user()];
+        }
+    }
+    return nil;
+}
+
+- (RLMSyncSessionState)state {
+    if (auto session = _session.lock()) {
+        if (session->state() == SyncSession::PublicState::Inactive) {
+            return RLMSyncSessionStateInactive;
+        }
+        if (session->state() != SyncSession::PublicState::Error) {
+            return RLMSyncSessionStateActive;
+        }
+    }
+    return RLMSyncSessionStateInvalid;
+}
+
+- (BOOL)waitForUploadCompletionOnQueue:(dispatch_queue_t)queue callback:(void(^)(NSError *))callback {
+    if (auto session = _session.lock()) {
+        if (session->state() == SyncSession::PublicState::Error) {
+            return NO;
+        }
+        queue = queue ?: dispatch_get_main_queue();
+        session->wait_for_upload_completion([=](std::error_code err) {
+            NSError *error = (err == std::error_code{}) ? nil : make_sync_error(err);
+            dispatch_async(queue, ^{
+                callback(error);
+            });
+        });
+        return YES;
+    }
+    return NO;
+}
+
+- (BOOL)waitForDownloadCompletionOnQueue:(dispatch_queue_t)queue callback:(void(^)(NSError *))callback {
+    if (auto session = _session.lock()) {
+        if (session->state() == SyncSession::PublicState::Error) {
+            return NO;
+        }
+        queue = queue ?: dispatch_get_main_queue();
+        session->wait_for_download_completion([=](std::error_code err) {
+            NSError *error = (err == std::error_code{}) ? nil : make_sync_error(err);
+            dispatch_async(queue, ^{
+                callback(error);
+            });
+        });
+        return YES;
+    }
+    return NO;
+}
+
+- (RLMProgressNotificationToken *)addProgressNotificationForDirection:(RLMSyncProgressDirection)direction
+                                                                 mode:(RLMSyncProgressMode)mode
+                                                                block:(RLMProgressNotificationBlock)block {
+    if (auto session = _session.lock()) {
+        if (session->state() == SyncSession::PublicState::Error) {
+            return nil;
+        }
+        dispatch_queue_t queue = RLMSyncSession.notificationsQueue;
+        auto notifier_direction = (direction == RLMSyncProgressDirectionUpload
+                                   ? SyncSession::NotifierType::upload
+                                   : SyncSession::NotifierType::download);
+        bool is_streaming = (mode == RLMSyncProgressModeReportIndefinitely);
+        uint64_t token = session->register_progress_notifier([=](uint64_t transferred, uint64_t transferrable) {
+            dispatch_async(queue, ^{
+                block((NSUInteger)transferred, (NSUInteger)transferrable);
+            });
+        }, notifier_direction, is_streaming);
+        return [[RLMProgressNotificationToken alloc] initWithTokenValue:token session:std::move(session)];
+    }
+    return nil;
+}
+
++ (void)immediatelyHandleError:(RLMSyncErrorActionToken *)token {
+    if (!token->_isValid) {
+        return;
+    }
+    token->_isValid = NO;
+    SyncManager::shared().immediately_run_file_actions(std::move(token->_originalPath));
+}
+
+@end
+
+// MARK: - Error action token
+
+@implementation RLMSyncErrorActionToken
+
+- (instancetype)initWithOriginalPath:(std::string)originalPath {
+    if (self = [super init]) {
+        _isValid = YES;
+        _originalPath = std::move(originalPath);
+        return self;
+    }
+    return nil;
+}
+
+@end