From 6f36efb81eade416dbec68b7124aa4251c4506cc Mon Sep 17 00:00:00 2001 From: Christian Melchior Date: Mon, 19 Nov 2018 10:45:58 +0100 Subject: [PATCH] Add support for a custom User Agent (#2114) --- CHANGELOG.md | 6 +++--- docs/sync.js | 12 +++++++++++- lib/index.d.ts | 1 + lib/index.js | 23 +++++++++++++++++++++++ src/js_sync.hpp | 24 +++++++++++++++++++----- src/object-store | 2 +- 6 files changed, 58 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 54d38ec1..3572c805 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,7 @@ x.x.x Release notes (yyyy-MM-dd) x.x.x Release notes (yyyy-MM-dd) ============================================================= ### Enhancements -* None. +* Adds support for setting a custom User-Agent string using `Realm.Sync.setUserAgent(...)`. This string will be sent to the server when creating a connection. ([#XXX]()) ### Fixed * Tokens are refreshed ahead of time. If the lifetime of the token is lower than the threshold for refreshing it will cause the client to continously refresh, spamming the server with refresh requests. A lower bound of 10 seconds has been introduced. ([#2115](https://github.com/realm/realm-js/issues/2115), since v1.0.2) @@ -28,8 +28,8 @@ x.x.x Release notes (yyyy-MM-dd) * APIs are backwards compatible with all previous release of realm in the 2.x.y series. * File format: Generates Realms with format v9 (Reads and upgrades all previous formats) - ### Internal -* None. +### Internal +* Upgrades to Object Store commit: 66eea3994f598a388a775b93acb1c13603cc65c3 2.19.1 Release notes (2018-11-15) ============================================================= diff --git a/docs/sync.js b/docs/sync.js index ca48d64a..f2d31429 100644 --- a/docs/sync.js +++ b/docs/sync.js @@ -170,6 +170,16 @@ class Sync { */ static setLogLevel(log_level) {} + /** + * Set the application part of the User-Agent string that will be sent to the Realm Object Server when a session + * is created. + * + * This method can only be called up to the point where the first Realm is opened. After that, the User-Agent + * can no longer be changed. + * @param {string} the user agent description + */ + static setUserAgent(userAgent) {} + /** * Initiate a client reset. The Realm must be closed prior to the reset. * @@ -252,7 +262,7 @@ class ChangeEvent { /** * @typedef Realm.Sync~LogLevel - * @type {("error"|"info"|"debug")} + * @type {("all"|"trace"|"debug"|"detail"|"info"|"warn"|"error"|"fatal"|"off")} */ /** diff --git a/lib/index.d.ts b/lib/index.d.ts index c808be80..10d9689a 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -540,6 +540,7 @@ declare namespace Realm.Sync { function removeAllListeners(): Promise; function removeListener(regex: string, name: string, changeCallback: (changeEvent: ChangeEvent) => void): Promise; function setLogLevel(logLevel: 'all' | 'trace' | 'debug' | 'detail' | 'info' | 'warn' | 'error' | 'fatal' | 'off'): void; + function setUserAgent(userAgent: string): void; function initiateClientReset(path: string): void; /** diff --git a/lib/index.js b/lib/index.js index 2dcc9a4b..bc3c307c 100644 --- a/lib/index.js +++ b/lib/index.js @@ -87,6 +87,28 @@ function getContext() { throw Error("Unknown execution context"); } +function createUserAgentDescription() { + // Detect if in ReactNative (running on a phone) or in a Node.js environment + // Credit: https://stackoverflow.com/questions/39468022/how-do-i-know-if-my-code-is-running-as-react-native + try { + var userAgent = "RealmJS/"; + var context = getContext(); + userAgent = userAgent + require('../package.json').version + " (" + context + ", "; + if (typeof navigator !== 'undefined' && navigator.product === 'ReactNative') { + // Running on ReactNative + const Platform = require('react-native').Platform; + userAgent += Platform.OS + ", v" + Platform.Version; + } else { + // Running on a normal machine + userAgent += process.version; + } + return userAgent += ")"; + } catch (e) { + return "RealmJS/Unknown" + } +} + + var realmConstructor; const context = getContext(); @@ -127,6 +149,7 @@ if (realmConstructor.Sync) { Object.defineProperty(realmConstructor, 'Worker', {value: nodeRequire('./worker')}); } } + realmConstructor.Sync._initializeSyncManager(createUserAgentDescription()); } module.exports = realmConstructor; diff --git a/src/js_sync.hpp b/src/js_sync.hpp index fafeca10..edefa0c1 100644 --- a/src/js_sync.hpp +++ b/src/js_sync.hpp @@ -45,11 +45,6 @@ namespace realm { namespace js { inline realm::SyncManager& syncManagerShared() { - static std::once_flag flag; - std::call_once(flag, [] { - ensure_directory_exists_for_file(default_realm_file_directory()); - SyncManager::shared().configure(default_realm_file_directory(), SyncManager::MetadataMode::NoEncryption); - }); return SyncManager::shared(); } @@ -847,7 +842,9 @@ public: static FunctionType create_constructor(ContextType); + static void initialize_sync_manager(ContextType, ObjectType, Arguments &, ReturnValue &); static void set_sync_log_level(ContextType, ObjectType, Arguments &, ReturnValue &); + static void set_sync_user_agent(ContextType, ObjectType, Arguments &, ReturnValue &); static void initiate_client_reset(ContextType, ObjectType, Arguments &, ReturnValue &); // private @@ -860,7 +857,9 @@ public: MethodMap const static_methods = { {"setLogLevel", wrap}, + {"setUserAgent", wrap}, {"initiateClientReset", wrap}, + {"_initializeSyncManager", wrap}, }; }; @@ -875,6 +874,14 @@ inline typename T::Function SyncClass::create_constructor(ContextType ctx) { return sync_constructor; } +template +void SyncClass::initialize_sync_manager(ContextType ctx, ObjectType this_object, Arguments &args, ReturnValue & return_value) { + args.validate_count(1); + std::string user_agent_binding_info = Value::validated_to_string(ctx, args[0]); + ensure_directory_exists_for_file(default_realm_file_directory()); + SyncManager::shared().configure(default_realm_file_directory(), SyncManager::MetadataMode::NoEncryption, user_agent_binding_info); +} + template void SyncClass::initiate_client_reset(ContextType ctx, ObjectType this_object, Arguments &args, ReturnValue & return_value) { args.validate_count(1); @@ -898,6 +905,13 @@ void SyncClass::set_sync_log_level(ContextType ctx, ObjectType this_object, A syncManagerShared().set_log_level(log_level_2); } +template +void SyncClass::set_sync_user_agent(ContextType ctx, ObjectType this_object, Arguments &args, ReturnValue &return_value) { + args.validate_count(1); + std::string application_user_agent = Value::validated_to_string(ctx, args[0]); + syncManagerShared().set_user_agent(application_user_agent); +} + template std::function SyncClass::session_bind_callback(ContextType ctx, ObjectType sync_constructor) { diff --git a/src/object-store b/src/object-store index 3253b505..66eea399 160000 --- a/src/object-store +++ b/src/object-store @@ -1 +1 @@ -Subproject commit 3253b5057573ee24e05d23b76505abb10e6deb32 +Subproject commit 66eea3994f598a388a775b93acb1c13603cc65c3