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 "RLMSyncSession_Private.hpp"
21 #import "RLMSyncConfiguration_Private.hpp"
22 #import "RLMSyncUser_Private.hpp"
23 #import "RLMSyncUtil_Private.hpp"
24 #import "sync/sync_session.hpp"
26 using namespace realm;
28 @interface RLMSyncErrorActionToken () {
30 std::string _originalPath;
35 @interface RLMProgressNotificationToken() {
37 std::weak_ptr<SyncSession> _session;
41 @implementation RLMProgressNotificationToken
43 - (void)suppressNextNotification {
44 // No-op, but implemented in case this token is passed to
45 // `-[RLMRealm commitWriteTransactionWithoutNotifying:]`.
49 if (auto session = _session.lock()) {
50 session->unregister_progress_notifier(_token);
58 NSLog(@"RLMProgressNotificationToken released without unregistering a notification. "
59 @"You must hold on to the RLMProgressNotificationToken and call "
60 @"-[RLMProgressNotificationToken invalidate] when you no longer wish to receive "
61 @"progress update notifications.");
65 - (nullable instancetype)initWithTokenValue:(uint64_t)token
66 session:(std::shared_ptr<SyncSession>)session {
70 if (self = [super init]) {
80 @interface RLMSyncSession ()
81 @property (class, nonatomic, readonly) dispatch_queue_t notificationsQueue;
84 @implementation RLMSyncSession
86 + (dispatch_queue_t)notificationsQueue {
87 static dispatch_queue_t queue;
88 static dispatch_once_t onceToken;
89 dispatch_once(&onceToken, ^{
90 queue = dispatch_queue_create("io.realm.sync.sessionsNotificationQueue", DISPATCH_QUEUE_SERIAL);
95 - (instancetype)initWithSyncSession:(std::shared_ptr<SyncSession>)session {
96 if (self = [super init]) {
103 - (RLMSyncConfiguration *)configuration {
104 if (auto session = _session.lock()) {
105 if (session->state() != SyncSession::PublicState::Error) {
106 return [[RLMSyncConfiguration alloc] initWithRawConfig:session->config()];
112 - (NSURL *)realmURL {
113 if (auto session = _session.lock()) {
114 if (auto url = session->full_realm_url()) {
115 return [NSURL URLWithString:@(url->c_str())];
121 - (RLMSyncUser *)parentUser {
122 if (auto session = _session.lock()) {
123 if (session->state() != SyncSession::PublicState::Error) {
124 return [[RLMSyncUser alloc] initWithSyncUser:session->user()];
130 - (RLMSyncSessionState)state {
131 if (auto session = _session.lock()) {
132 if (session->state() == SyncSession::PublicState::Inactive) {
133 return RLMSyncSessionStateInactive;
135 if (session->state() != SyncSession::PublicState::Error) {
136 return RLMSyncSessionStateActive;
139 return RLMSyncSessionStateInvalid;
142 - (BOOL)waitForUploadCompletionOnQueue:(dispatch_queue_t)queue callback:(void(^)(NSError *))callback {
143 if (auto session = _session.lock()) {
144 if (session->state() == SyncSession::PublicState::Error) {
147 queue = queue ?: dispatch_get_main_queue();
148 session->wait_for_upload_completion([=](std::error_code err) {
149 NSError *error = (err == std::error_code{}) ? nil : make_sync_error(err);
150 dispatch_async(queue, ^{
159 - (BOOL)waitForDownloadCompletionOnQueue:(dispatch_queue_t)queue callback:(void(^)(NSError *))callback {
160 if (auto session = _session.lock()) {
161 if (session->state() == SyncSession::PublicState::Error) {
164 queue = queue ?: dispatch_get_main_queue();
165 session->wait_for_download_completion([=](std::error_code err) {
166 NSError *error = (err == std::error_code{}) ? nil : make_sync_error(err);
167 dispatch_async(queue, ^{
176 - (RLMProgressNotificationToken *)addProgressNotificationForDirection:(RLMSyncProgressDirection)direction
177 mode:(RLMSyncProgressMode)mode
178 block:(RLMProgressNotificationBlock)block {
179 if (auto session = _session.lock()) {
180 if (session->state() == SyncSession::PublicState::Error) {
183 dispatch_queue_t queue = RLMSyncSession.notificationsQueue;
184 auto notifier_direction = (direction == RLMSyncProgressDirectionUpload
185 ? SyncSession::NotifierType::upload
186 : SyncSession::NotifierType::download);
187 bool is_streaming = (mode == RLMSyncProgressModeReportIndefinitely);
188 uint64_t token = session->register_progress_notifier([=](uint64_t transferred, uint64_t transferrable) {
189 dispatch_async(queue, ^{
190 block((NSUInteger)transferred, (NSUInteger)transferrable);
192 }, notifier_direction, is_streaming);
193 return [[RLMProgressNotificationToken alloc] initWithTokenValue:token session:std::move(session)];
198 + (void)immediatelyHandleError:(RLMSyncErrorActionToken *)token {
199 if (!token->_isValid) {
202 token->_isValid = NO;
203 SyncManager::shared().immediately_run_file_actions(std::move(token->_originalPath));
208 // MARK: - Error action token
210 @implementation RLMSyncErrorActionToken
212 - (instancetype)initWithOriginalPath:(std::string)originalPath {
213 if (self = [super init]) {
215 _originalPath = std::move(originalPath);