123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247 |
- ////////////////////////////////////////////////////////////////////////////
- //
- // 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 "RLMRealm_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;
- @property (atomic, readwrite) RLMSyncConnectionState connectionState;
- @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;
- }
- 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 {
- if (self = [super init]) {
- _session = session;
- _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) {
- dispatch_async(dispatch_get_main_queue(), ^{
- self.connectionState = convertConnectionState(newState);
- });
- });
- return self;
- }
- return nil;
- }
- - (RLMSyncConfiguration *)configuration {
- if (auto session = _session.lock()) {
- 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()) {
- return [[RLMSyncUser alloc] initWithSyncUser:session->user()];
- }
- return nil;
- }
- - (RLMSyncSessionState)state {
- if (auto session = _session.lock()) {
- if (session->state() == SyncSession::PublicState::Inactive) {
- return RLMSyncSessionStateInactive;
- }
- return RLMSyncSessionStateActive;
- }
- return RLMSyncSessionStateInvalid;
- }
- - (void)suspend {
- if (auto session = _session.lock()) {
- session->log_out();
- }
- }
- - (void)resume {
- if (auto session = _session.lock()) {
- session->revive_if_needed();
- }
- }
- - (BOOL)waitForUploadCompletionOnQueue:(dispatch_queue_t)queue callback:(void(^)(NSError *))callback {
- if (auto session = _session.lock()) {
- 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()) {
- 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()) {
- 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));
- }
- + (nullable RLMSyncSession *)sessionForRealm:(RLMRealm *)realm {
- auto& config = realm->_realm->config().sync_config;
- if (!config) {
- return nil;
- }
- if (auto session = config->user->session_for_on_disk_path(realm->_realm->config().path)) {
- return [[RLMSyncSession alloc] initWithSyncSession:session];
- }
- return nil;
- }
- @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
|