Add support for sync pause/resume (#2019)

* Add support for sync pause/resume
* Improve the promise chain in the tests
* Update CHANGELOG.md
* Update sync.js
This commit is contained in:
Emanuele Zattin 2018-09-12 16:04:22 +02:00 committed by Kenneth Geisshirt
parent f45ba1c9e7
commit 9314ee0a7d
6 changed files with 168 additions and 0 deletions

View File

@ -11,6 +11,7 @@ X.Y.Z Release notes
* Exposed `User.serialize` to create a persistable representation of a user instance, as well as
`User.deserialize` to later inflate a `User` instance that can be used to connect to Realm Object
Server and open synchronized Realms (#1276).
* Added `Session.start()` and `Session.stop()` in order to allow stopping to sync data (#2014).
* Added support for `LIMIT` in queries to restrict the size of the results set. This is in particular useful for query-based synced Realms. An example of the syntax is `age >= 20 LIMIT(2)`.
### Bug fixes

View File

@ -651,6 +651,26 @@ class Session {
*/
isConnected() {}
/**
* Starts a sync session.
*
* This method is asynchronous so in order to know when the session has started you will need
* to add a connection notification with `addConnectionNotification`.
*
* This method is idempotent so it will be a no-op if the session has already started.
*/
start() {}
/**
* Stops a sync session.
*
* This method is asynchronous so in order to know when the session has started you will need
* to add a connection notification with `addConnectionNotification`.
*
* This method is idempotent so it will be a no-op if the session has already stopped.
*/
stop() {}
}
/**

View File

@ -39,6 +39,8 @@ createMethods(Session.prototype, objectTypes.SESSION, [
'addConnectionNotification',
'removeConnectionNotification',
'isConnected',
'start',
'stop',
]);
export function createSession(realmId, info) {

3
lib/index.d.ts vendored
View File

@ -470,6 +470,9 @@ declare namespace Realm.Sync {
removeConnectionNotification(callback: ConnectionNotificationCallback): void;
isConnected(): boolean;
start(): void;
stop(): void;
}
type SubscriptionNotificationCallback = (subscription: Subscription, state: number) => void;

View File

@ -233,6 +233,8 @@ public:
static void add_connection_notification(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &);
static void remove_connection_notification(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &);
static void is_connected(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &);
static void start(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &);
static void stop(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &);
static void override_server(ContextType ctx, ObjectType this_object, Arguments args, ReturnValue&);
@ -254,6 +256,8 @@ public:
{"addConnectionNotification", wrap<add_connection_notification>},
{"removeConnectionNotification", wrap<remove_connection_notification>},
{"isConnected", wrap<is_connected>},
{"start", wrap<start>},
{"stop", wrap<stop>},
};
private:
@ -646,6 +650,24 @@ void SessionClass<T>::is_connected(ContextType ctx, FunctionType, ObjectType thi
}
}
template<typename T>
void SessionClass<T>::start(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 0);
return_value.set(false);
if (auto session = get_internal<T, SessionClass<T>>(this_object)->lock()) {
session->revive_if_needed();
}
}
template<typename T>
void SessionClass<T>::stop(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
validate_argument_count(argc, 0);
return_value.set(false);
if (auto session = get_internal<T, SessionClass<T>>(this_object)->lock()) {
session->log_out();
}
}
template<typename T>
void SessionClass<T>::override_server(ContextType ctx, ObjectType this_object, Arguments args, ReturnValue&) {
args.validate_count(2);

View File

@ -84,6 +84,16 @@ function runOutOfProcess() {
});
}
function waitForSessionConnected(session) {
return new Promise(res => {
session.addConnectionNotification((newState, oldState) => {
if (newState === Realm.Sync.ConnectionState.Connected) {
res();
}
})
});
}
module.exports = {
testLocalRealmHasNoSession() {
let realm = new Realm();
@ -1041,11 +1051,121 @@ module.exports = {
resolve('Done');
}
});
setTimeout(() => { reject() }, 10000);
}).catch(error => reject(error));
});
});
},
testStartStop() {
if(!isNodeProccess) {
return;
}
return Realm.Sync.User.register('http://localhost:9080', uuid(), 'password')
.then((user) => {
const config = {
sync: {
user: user,
url: `realm://localhost:9080/~/${uuid()}`,
fullSynchronization: true,
}
};
return Realm.open(config);
}).then((realm) => {
return new Promise((resolve, reject) => {
const session = realm.syncSession;
const checks = {
started: false,
stopped: false,
restarted: false
}
session.addConnectionNotification((newState, oldState) => {
if (newState === Realm.Sync.ConnectionState.Connected && checks.started === false) { checks.started = true; session.stop(); }
if (newState === Realm.Sync.ConnectionState.Connected && checks.started === true) { checks.restarted = true; resolve(); }
if (newState === Realm.Sync.ConnectionState.Disconnected) { checks.stopped = true; session.start();}
});
setTimeout(() => { reject("Timeout") }, 10000);
})
})
},
testMultipleStarts() {
if(!isNodeProccess) {
return;
}
return Realm.Sync.User.register('http://localhost:9080', uuid(), 'password')
.then((user) => {
const config = {
sync: {
user: user,
url: `realm://localhost:9080/~/${uuid()}`,
fullSynchronization: true,
}
};
return Realm.open(config)
}).then(realm => {
return new Promise((resolve, reject) => {
const session = realm.syncSession;
waitForSessionConnected(session).then(() => {
session.start();
session.start();
session.start();
setTimeout(() => {
if (session.isConnected()) {
resolve();
} else {
reject();
}
}, 1000);
})
})
})
},
testMultipleStopped() {
if(!isNodeProccess) {
return;
}
return Realm.Sync.User.register('http://localhost:9080', uuid(), 'password')
.then((user) => {
const config = {
sync: {
user: user,
url: `realm://localhost:9080/~/${uuid()}`,
fullSynchronization: true,
}
};
return Realm.open(config)
}).then(realm => {
return new Promise((resolve, reject) => {
const session = realm.syncSession;
waitForSessionConnected(session).then(() => {
session.stop();
session.stop();
session.stop();
setTimeout(() => {
if (session.isConnected()) {
reject();
} else {
resolve();
}
}, 1000);
})
})
})
},
testOfflinePermissionSchemas() {
if (!isNodeProccess) {
return;