Client reset (#1341)
This commit is contained in:
parent
33c4a886d0
commit
fe121ea27b
|
@ -5,6 +5,7 @@ X.Y.Z-rc Release notes
|
|||
|
||||
### Enhancements
|
||||
* Support migration from Realms sync 1.0 to sync 2.0 versions
|
||||
* Handling of the situation when the client has to reset the Realm due to diverging histories (#795).
|
||||
|
||||
### Bug fixes
|
||||
* None
|
||||
|
|
17
docs/sync.js
17
docs/sync.js
|
@ -62,7 +62,22 @@ class Sync {
|
|||
*/
|
||||
static setLogLevel(log_level) {}
|
||||
|
||||
|
||||
/**
|
||||
* Initiate a client reset. The Realm must be closed prior to the reset.
|
||||
* @param {string} [path] - The Realm to reset.
|
||||
* Throws error if reset is not possible.
|
||||
* @example
|
||||
* {
|
||||
* const config = { sync: { user, url: 'realm://localhost:9080/~/myrealm' } };
|
||||
* config.sync.error = (sender, error) => {
|
||||
* if (error.code === 7) { // 7 -> client reset
|
||||
* Realm.Sync.initiateClientReset(original_path);
|
||||
* // copy required objects from Realm at error.config.path
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
static initiateClientReset(path) {}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -79,7 +79,7 @@ module.exports = function(realmConstructor) {
|
|||
openAsync(config, callback, progressCallback) {
|
||||
const message = "Realm.openAsync is now deprecated in favor of Realm.open. This function will be removed in future versions.";
|
||||
(console.warn || console.log).call(console, message);
|
||||
|
||||
|
||||
realmConstructor._waitForDownload(config,
|
||||
(syncSession) => {
|
||||
if (progressCallback) {
|
||||
|
|
|
@ -415,6 +415,7 @@ declare namespace Realm.Sync {
|
|||
function removeAllListeners(name?: string): void;
|
||||
function removeListener(regex: string, name: string, changeCallback: (changeEvent: ChangeEvent) => void): void;
|
||||
function setLogLevel(logLevel: 'all' | 'trace' | 'debug' | 'detail' | 'info' | 'warn' | 'error' | 'fatal' | 'off'): void;
|
||||
function initiateClientReset(path: string): void;
|
||||
function setFeatureToken(token: string): void;
|
||||
|
||||
/**
|
||||
|
|
|
@ -229,10 +229,21 @@ public:
|
|||
HANDLESCOPE
|
||||
|
||||
auto error_object = Object<T>::create_empty(m_ctx);
|
||||
|
||||
auto error_code = error.error_code.value();
|
||||
if (error.is_client_reset_requested()) {
|
||||
error_code = 7; // FIXME: define a proper constant
|
||||
|
||||
auto config_object = Object<T>::create_empty(m_ctx);
|
||||
Object<T>::set_property(m_ctx, config_object, "path", Value<T>::from_string(m_ctx, error.user_info[SyncError::c_recovery_file_path_key]));
|
||||
Object<T>::set_property(m_ctx, config_object, "readOnly", Value<T>::from_boolean(m_ctx, true));
|
||||
Object<T>::set_property(m_ctx, error_object, "config", config_object);
|
||||
}
|
||||
|
||||
Object<T>::set_property(m_ctx, error_object, "message", Value<T>::from_string(m_ctx, error.message));
|
||||
Object<T>::set_property(m_ctx, error_object, "isFatal", Value<T>::from_boolean(m_ctx, error.is_fatal));
|
||||
Object<T>::set_property(m_ctx, error_object, "category", Value<T>::from_string(m_ctx, error.error_code.category().name()));
|
||||
Object<T>::set_property(m_ctx, error_object, "code", Value<T>::from_number(m_ctx, error.error_code.value()));
|
||||
Object<T>::set_property(m_ctx, error_object, "code", Value<T>::from_number(m_ctx, error_code));
|
||||
|
||||
auto user_info = Object<T>::create_empty(m_ctx);
|
||||
for (auto& kvp : error.user_info) {
|
||||
|
@ -478,9 +489,7 @@ void SessionClass<T>::add_progress_notification(ContextType ctx, FunctionType, O
|
|||
|
||||
progressFunc = std::move(progress_handler);
|
||||
|
||||
|
||||
auto registrationToken = session->register_progress_notifier(std::move(progressFunc), notifierType, is_streaming);
|
||||
|
||||
auto syncSession = create_object<T, SessionClass<T>>(ctx, new WeakSession(session));
|
||||
PropertyAttributes attributes = ReadOnly | DontEnum | DontDelete;
|
||||
Object::set_property(ctx, callback_function, "_syncSession", syncSession, attributes);
|
||||
|
@ -525,6 +534,7 @@ public:
|
|||
static FunctionType create_constructor(ContextType);
|
||||
|
||||
static void set_sync_log_level(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue &);
|
||||
static void initiate_client_reset(ContextType, FunctionType, ObjectType, size_t, const ValueType[], ReturnValue &);
|
||||
|
||||
// private
|
||||
static std::function<SyncBindSessionHandler> session_bind_callback(ContextType ctx, ObjectType sync_constructor);
|
||||
|
@ -535,6 +545,7 @@ public:
|
|||
|
||||
MethodMap<T> const static_methods = {
|
||||
{"setLogLevel", wrap<set_sync_log_level>},
|
||||
{"initiateClientReset", wrap<initiate_client_reset>},
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -549,6 +560,15 @@ inline typename T::Function SyncClass<T>::create_constructor(ContextType ctx) {
|
|||
return sync_constructor;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void SyncClass<T>::initiate_client_reset(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue & return_value) {
|
||||
validate_argument_count(argc, 1);
|
||||
std::string path = Value::validated_to_string(ctx, arguments[0]);
|
||||
if (!SyncManager::shared().immediately_run_file_actions(std::string(path))) {
|
||||
throw std::runtime_error(util::format("Realm was not configured correctly. Client Reset could not be run for Realm at: %1", path));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void SyncClass<T>::set_sync_log_level(ContextType ctx, FunctionType, ObjectType this_object, size_t argc, const ValueType arguments[], ReturnValue &return_value) {
|
||||
validate_argument_count(argc, 1);
|
||||
|
|
|
@ -780,4 +780,38 @@ module.exports = {
|
|||
});
|
||||
});
|
||||
},
|
||||
|
||||
testClientReset() {
|
||||
// FIXME: try to enable for React Native
|
||||
if (!isNodeProccess) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return Realm.Sync.User.register('http://localhost:9080', uuid(), 'password').then(user => {
|
||||
return new Promise((resolve, _reject) => {
|
||||
var realm;
|
||||
const config = { sync: { user, url: 'realm://localhost:9080/~/myrealm' } };
|
||||
config.sync.error = (sender, error) => {
|
||||
try {
|
||||
TestCase.assertEqual(error.code, 7); // 7 -> client reset
|
||||
TestCase.assertDefined(error.config);
|
||||
TestCase.assertNotEqual(error.config.path, '');
|
||||
const original_path = realm.path;
|
||||
realm.close();
|
||||
Realm.Sync.initiateClientReset(original_path);
|
||||
// copy required objects from Realm at error.config.path
|
||||
resolve();
|
||||
}
|
||||
catch (e) {
|
||||
_reject(e);
|
||||
}
|
||||
};
|
||||
realm = new Realm(config);
|
||||
const session = realm.syncSession;
|
||||
|
||||
TestCase.assertEqual(session.config.error, config.sync.error);
|
||||
session._simulateError(211, 'ClientReset'); // 211 -> divering histories
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue