RLMSyncSession.mm 7.63 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
////////////////////////////////////////////////////////////////////////////
//
// 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"

Zach Knox's avatar
Zach Knox committed
21
#import "RLMRealm_Private.hpp"
22
23
#import "RLMSyncConfiguration_Private.hpp"
#import "RLMSyncUser_Private.hpp"
24
#import "RLMSyncUtil_Private.hpp"
25
26
27
28
#import "sync/sync_session.hpp"

using namespace realm;

29
30
31
32
33
34
35
@interface RLMSyncErrorActionToken () {
@public
    std::string _originalPath;
    BOOL _isValid;
}
@end

36
37
38
39
40
41
42
43
44
45
46
47
48
@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:]`.
}

49
- (void)invalidate {
50
51
52
53
54
55
56
57
58
59
60
    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 "
61
              @"-[RLMProgressNotificationToken invalidate] when you no longer wish to receive "
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
              @"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;
83
@property (atomic, readwrite) RLMSyncConnectionState connectionState;
84
85
86
87
88
89
90
91
92
93
94
95
96
@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;
}

97
98
99
100
101
102
103
104
105
static RLMSyncConnectionState convertConnectionState(SyncSession::ConnectionState state) {
    switch (state) {
        case SyncSession::ConnectionState::Disconnected: return RLMSyncConnectionStateDisconnected;
        case SyncSession::ConnectionState::Connecting:   return RLMSyncConnectionStateConnecting;
        case SyncSession::ConnectionState::Connected:    return RLMSyncConnectionStateConnected;
    }
}

- (instancetype)initWithSyncSession:(std::shared_ptr<SyncSession> const&)session {
106
107
    if (self = [super init]) {
        _session = session;
108
109
110
111
112
113
        _connectionState = convertConnectionState(session->connection_state());
        // No need to save the token as RLMSyncSession always outlives the
        // underlying SyncSession
        session->register_connection_change_callback([=](auto, auto newState) {
            self.connectionState = convertConnectionState(newState);
        });
114
115
116
117
118
119
120
        return self;
    }
    return nil;
}

- (RLMSyncConfiguration *)configuration {
    if (auto session = _session.lock()) {
121
        return [[RLMSyncConfiguration alloc] initWithRawConfig:session->config()];
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
    }
    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()) {
137
        return [[RLMSyncUser alloc] initWithSyncUser:session->user()];
138
139
140
141
142
143
144
145
146
    }
    return nil;
}

- (RLMSyncSessionState)state {
    if (auto session = _session.lock()) {
        if (session->state() == SyncSession::PublicState::Inactive) {
            return RLMSyncSessionStateInactive;
        }
147
        return RLMSyncSessionStateActive;
148
149
150
151
    }
    return RLMSyncSessionStateInvalid;
}

152
153
154
155
156
157
158
159
160
161
162
163
- (void)suspend {
    if (auto session = _session.lock()) {
        session->log_out();
    }
}

- (void)resume {
    if (auto session = _session.lock()) {
        session->revive_if_needed();
    }
}

164
- (BOOL)waitForUploadCompletionOnQueue:(dispatch_queue_t)queue callback:(void(^)(NSError *))callback {
165
166
    if (auto session = _session.lock()) {
        queue = queue ?: dispatch_get_main_queue();
167
168
169
170
171
        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);
            });
172
173
174
175
176
177
        });
        return YES;
    }
    return NO;
}

178
- (BOOL)waitForDownloadCompletionOnQueue:(dispatch_queue_t)queue callback:(void(^)(NSError *))callback {
179
180
    if (auto session = _session.lock()) {
        queue = queue ?: dispatch_get_main_queue();
181
182
183
184
185
        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);
            });
186
187
188
189
190
191
192
        });
        return YES;
    }
    return NO;
}

- (RLMProgressNotificationToken *)addProgressNotificationForDirection:(RLMSyncProgressDirection)direction
193
                                                                 mode:(RLMSyncProgressMode)mode
194
195
196
197
198
199
                                                                block:(RLMProgressNotificationBlock)block {
    if (auto session = _session.lock()) {
        dispatch_queue_t queue = RLMSyncSession.notificationsQueue;
        auto notifier_direction = (direction == RLMSyncProgressDirectionUpload
                                   ? SyncSession::NotifierType::upload
                                   : SyncSession::NotifierType::download);
200
        bool is_streaming = (mode == RLMSyncProgressModeReportIndefinitely);
201
202
203
204
205
206
207
208
209
210
        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;
}

211
212
213
214
215
216
217
218
+ (void)immediatelyHandleError:(RLMSyncErrorActionToken *)token {
    if (!token->_isValid) {
        return;
    }
    token->_isValid = NO;
    SyncManager::shared().immediately_run_file_actions(std::move(token->_originalPath));
}

Zach Knox's avatar
Zach Knox committed
219
220
221
222
223
+ (nullable RLMSyncSession *)sessionForRealm:(RLMRealm *)realm {
    auto& config = realm->_realm->config().sync_config;
    if (!config) {
        return nil;
    }
224
    if (auto session = config->user->session_for_on_disk_path(realm->_realm->config().path)) {
Zach Knox's avatar
Zach Knox committed
225
226
227
228
229
        return [[RLMSyncSession alloc] initWithSyncSession:session];
    }
    return nil;
}

230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
@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;
}

245
@end