Skip to content

Commit

Permalink
Support opening a synchronized realm without synchronizing (#621)
Browse files Browse the repository at this point in the history
* Support opening a synchronized realm without synchronizing

Use the new `SyncFollowerConfiguration` to open a synchronized realm,
without actually starting a sync session.

* Rename SyncFollowerConfiguration to SessionlessSyncConfiguration

* Add simple test for SessionlessSyncConfiguration

* Rename to DisconnectedSyncConfiguration

* Update CHANGELOG.md

* Run build despite vcpkg failure to setup vcpkg

* Fix subscription_test.dart

* Remove Realm.startup()

* Update doc comment in lib/src/configuration.dart

Co-authored-by: blagoev <[email protected]>

* Apply suggestions from code review

Co-authored-by: blagoev <[email protected]>
  • Loading branch information
nielsenko and blagoev authored Jun 13, 2022
1 parent 268ca27 commit 0e5dbc4
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 9 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ jobs:
run: echo "::set-output name=commit::$(git rev-parse HEAD)"

- name: Setup Vcpkg
continue-on-error: true
if: contains(github.head_ref, 'release/') || steps.check-cache.outputs.cache-hit != 'true'
uses: friendlyanon/setup-vcpkg@v1
with:
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## vNext

**This project is in the Beta stage. The API should be quite stable, but occasional breaking changes may be made.**
### Enhancements
* Added `DisconnectedSyncConfiguration` for opening a synchronized realm in a disconnected state. This configuration allows a synchronized realm to be opened by a secondary process, while a primary process handles synchronization. ([#621](https://github.com/realm/realm-dart/pull/621))

## 0.3.1+beta (2022-06-07)

**This project is in the Beta stage. The API should be quite stable, but occasional breaking changes may be made.**
Expand Down
44 changes: 36 additions & 8 deletions lib/src/configuration.dart
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,18 @@ abstract class Configuration {
syncErrorHandler: syncErrorHandler,
syncClientResetErrorHandler: syncClientResetErrorHandler,
);

/// Constructs a [DisconnectedSyncConfiguration]
static DisconnectedSyncConfiguration disconnectedSync(
List<SchemaObject> schemaObjects, {
String? fifoFilesFallbackPath,
String? path,
}) =>
DisconnectedSyncConfiguration._(
schemaObjects,
fifoFilesFallbackPath: fifoFilesFallbackPath,
path: path,
);
}

extension ConfigurationInternal on Configuration {
Expand Down Expand Up @@ -214,32 +226,35 @@ enum SessionStopPolicy {
typedef SyncErrorHandler = void Function(SyncError);

void defaultSyncErrorHandler(SyncError e) {
Realm.logger.log(RealmLogLevel.error, e);
Realm.logger.log(RealmLogLevel.error, e);
}

void _defaultSyncClientResetHandler(SyncError e) {
Realm.logger.log(RealmLogLevel.error, "A client reset error occurred but no handler was supplied. "
"Synchronization is now paused and will resume automatically once the app is restarted and "
"the server data is redownloaded. Any unsynchronized changes the client has made or will "
"make will be lost. To handle that scenario, pass in a non-null value to "
"syncClientResetErrorHandler when constructing Configuration.flexibleSync.");
Realm.logger.log(
RealmLogLevel.error,
"A client reset error occurred but no handler was supplied. "
"Synchronization is now paused and will resume automatically once the app is restarted and "
"the server data is re-downloaded. Any un-synchronized changes the client has made or will "
"make will be lost. To handle that scenario, pass in a non-null value to "
"syncClientResetErrorHandler when constructing Configuration.flexibleSync.");
}

/// [FlexibleSyncConfiguration] is used to open [Realm] instances that are synchronized
/// with MongoDB Atlas.
/// {@category Configuration}
class FlexibleSyncConfiguration extends Configuration {
/// The [User] used to created this [FlexibleSyncConfiguration]
final User user;

SessionStopPolicy _sessionStopPolicy = SessionStopPolicy.afterChangesUploaded;

/// Called when a [SyncError] occurs for this synchronized [Realm].
///
///
/// The default [SyncErrorHandler] prints to the console
final SyncErrorHandler syncErrorHandler;

/// Called when a [SyncClientResetError] occurs for this synchronized [Realm]
///
///
/// The default [SyncClientResetErrorHandler] logs a message using the current Realm.logger
final SyncClientResetErrorHandler syncClientResetErrorHandler;

Expand All @@ -263,6 +278,19 @@ extension FlexibleSyncConfigurationInternal on FlexibleSyncConfiguration {
set sessionStopPolicy(SessionStopPolicy value) => _sessionStopPolicy = value;
}

/// [DisconnectedSyncConfiguration] is used to open [Realm] instances that are synchronized
/// with MongoDB Atlas, without establishing a connection to Atlas App Services. This allows
/// for the synchronized realm to be opened in multiple processes concurrently, as long as
/// only one of them uses a [FlexibleSyncConfiguration] to sync changes.
/// {@category Configuration}
class DisconnectedSyncConfiguration extends Configuration {
DisconnectedSyncConfiguration._(
super.schemaObjects, {
super.fifoFilesFallbackPath,
super.path,
}) : super._();
}

/// [InMemoryConfiguration] is used to open [Realm] instances that
/// are temporary to running process.
/// {@category Configuration}
Expand Down
2 changes: 2 additions & 0 deletions lib/src/native/realm_core.dart
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,8 @@ class _RealmCore {
} finally {
_realmLib.realm_release(syncConfigPtr.cast());
}
} else if (config is DisconnectedSyncConfiguration) {
_realmLib.realm_config_set_force_sync_history(configPtr, true);
}

return configHandle;
Expand Down
23 changes: 23 additions & 0 deletions test/configuration_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import 'dart:io';
import 'dart:math';
import 'package:test/test.dart' hide test, throws;
import 'package:path/path.dart' as path;
import '../lib/realm.dart';
import 'test.dart';

Expand Down Expand Up @@ -412,4 +413,26 @@ Future<void> main([List<String>? args]) async {

expect(config.path, 'my-custom-path.realm');
});

baasTest('Configuration.disconnectedSync', (appConfig) async {
final app = App(appConfig);
final user = await app.logIn(Credentials.emailPassword(testUsername, testPassword));

final dir = await Directory.systemTemp.createTemp();
final realmPath = path.join(dir.path, 'test.realm');

final schema = [Task.schema];
final flexibleSyncConfig = Configuration.flexibleSync(user, schema, path: realmPath);
final realm = Realm(flexibleSyncConfig);
final oid = ObjectId();
realm.subscriptions.update((mutableSubscriptions) {
mutableSubscriptions.add(realm.query<Task>(r'_id == $0', [oid]));
});
realm.write(() => realm.add(Task(oid)));
realm.close();

final disconnectedSyncConfig = Configuration.disconnectedSync(schema, path: realmPath);
final disconnectedRealm = Realm(disconnectedSyncConfig);
expect(disconnectedRealm.find<Task>(oid), isNotNull);
});
}
2 changes: 1 addition & 1 deletion test/subscription_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ import 'package:meta/meta.dart';
import 'package:test/expect.dart';

import '../lib/realm.dart';
import '../lib/src/configuration.dart';
import '../lib/src/native/realm_core.dart';
import '../lib/src/subscription.dart';

import 'test.dart';

@isTest
Expand Down

0 comments on commit 0e5dbc4

Please sign in to comment.