added iOS source code
[wl-app.git] / iOS / Pods / Realm / Realm / RLMSyncSession.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 "RLMSyncSession_Private.hpp"
20
21 #import "RLMSyncConfiguration_Private.hpp"
22 #import "RLMSyncUser_Private.hpp"
23 #import "RLMSyncUtil_Private.hpp"
24 #import "sync/sync_session.hpp"
25
26 using namespace realm;
27
28 @interface RLMSyncErrorActionToken () {
29 @public
30     std::string _originalPath;
31     BOOL _isValid;
32 }
33 @end
34
35 @interface RLMProgressNotificationToken() {
36     uint64_t _token;
37     std::weak_ptr<SyncSession> _session;
38 }
39 @end
40
41 @implementation RLMProgressNotificationToken
42
43 - (void)suppressNextNotification {
44     // No-op, but implemented in case this token is passed to
45     // `-[RLMRealm commitWriteTransactionWithoutNotifying:]`.
46 }
47
48 - (void)invalidate {
49     if (auto session = _session.lock()) {
50         session->unregister_progress_notifier(_token);
51         _session.reset();
52         _token = 0;
53     }
54 }
55
56 - (void)dealloc {
57     if (_token != 0) {
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.");
62     }
63 }
64
65 - (nullable instancetype)initWithTokenValue:(uint64_t)token
66                                     session:(std::shared_ptr<SyncSession>)session {
67     if (token == 0) {
68         return nil;
69     }
70     if (self = [super init]) {
71         _token = token;
72         _session = session;
73         return self;
74     }
75     return nil;
76 }
77
78 @end
79
80 @interface RLMSyncSession ()
81 @property (class, nonatomic, readonly) dispatch_queue_t notificationsQueue;
82 @end
83
84 @implementation RLMSyncSession
85
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);
91     });
92     return queue;
93 }
94
95 - (instancetype)initWithSyncSession:(std::shared_ptr<SyncSession>)session {
96     if (self = [super init]) {
97         _session = session;
98         return self;
99     }
100     return nil;
101 }
102
103 - (RLMSyncConfiguration *)configuration {
104     if (auto session = _session.lock()) {
105         if (session->state() != SyncSession::PublicState::Error) {
106             return [[RLMSyncConfiguration alloc] initWithRawConfig:session->config()];
107         }
108     }
109     return nil;
110 }
111
112 - (NSURL *)realmURL {
113     if (auto session = _session.lock()) {
114         if (auto url = session->full_realm_url()) {
115             return [NSURL URLWithString:@(url->c_str())];
116         }
117     }
118     return nil;
119 }
120
121 - (RLMSyncUser *)parentUser {
122     if (auto session = _session.lock()) {
123         if (session->state() != SyncSession::PublicState::Error) {
124             return [[RLMSyncUser alloc] initWithSyncUser:session->user()];
125         }
126     }
127     return nil;
128 }
129
130 - (RLMSyncSessionState)state {
131     if (auto session = _session.lock()) {
132         if (session->state() == SyncSession::PublicState::Inactive) {
133             return RLMSyncSessionStateInactive;
134         }
135         if (session->state() != SyncSession::PublicState::Error) {
136             return RLMSyncSessionStateActive;
137         }
138     }
139     return RLMSyncSessionStateInvalid;
140 }
141
142 - (BOOL)waitForUploadCompletionOnQueue:(dispatch_queue_t)queue callback:(void(^)(NSError *))callback {
143     if (auto session = _session.lock()) {
144         if (session->state() == SyncSession::PublicState::Error) {
145             return NO;
146         }
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, ^{
151                 callback(error);
152             });
153         });
154         return YES;
155     }
156     return NO;
157 }
158
159 - (BOOL)waitForDownloadCompletionOnQueue:(dispatch_queue_t)queue callback:(void(^)(NSError *))callback {
160     if (auto session = _session.lock()) {
161         if (session->state() == SyncSession::PublicState::Error) {
162             return NO;
163         }
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, ^{
168                 callback(error);
169             });
170         });
171         return YES;
172     }
173     return NO;
174 }
175
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) {
181             return nil;
182         }
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);
191             });
192         }, notifier_direction, is_streaming);
193         return [[RLMProgressNotificationToken alloc] initWithTokenValue:token session:std::move(session)];
194     }
195     return nil;
196 }
197
198 + (void)immediatelyHandleError:(RLMSyncErrorActionToken *)token {
199     if (!token->_isValid) {
200         return;
201     }
202     token->_isValid = NO;
203     SyncManager::shared().immediately_run_file_actions(std::move(token->_originalPath));
204 }
205
206 @end
207
208 // MARK: - Error action token
209
210 @implementation RLMSyncErrorActionToken
211
212 - (instancetype)initWithOriginalPath:(std::string)originalPath {
213     if (self = [super init]) {
214         _isValid = YES;
215         _originalPath = std::move(originalPath);
216         return self;
217     }
218     return nil;
219 }
220
221 @end