Skip to content

Commit c579d7b

Browse files
tgoyneironage
andcommitted
Rework sync user handling and metadata storage
This introduces the beginning of a split between sync and app services. Object store Sync types (almost) don't depend on the `app` namespace, and can be used independently of it. The SyncUser type now implements only the functionality required internally for sync, and is backed by a UserProvider interface which allows it to request things like access token refreshes. All user management has been removed from SyncManager, and it now only owns the sync client and active sync sessions. SyncSession is mostly unchanged. `app::User` is the new equivalent of the old SyncUser type. The user management which used to be in SyncManager is now in App, which implements the UserProvider interface. Metadata storage for sync and App has been completely redesigned. The metadata store is no longer optional, and instead has an in-memory implementation that should work identically to the persistent store other than not being persistent. The interface has been reworked to enable atomic updates to the metadata store rather than relying on the filesystem mutex in SyncManager, which will be required for multiprocess sync. This required pushing significantly more logic into the metadata storage, which fortunately turned out to also simplify things in the process. The ownership relationship between `App` and `User` has been inverted, with `App` now holding a weak cache of users and `User` strongly retaining the `App`. This ensures that a `SyncConfig` now retains everything it depends on even when app caching is not used. Co-authored-by: James Stone <[email protected]>
1 parent 1bb10e7 commit c579d7b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+3885
-4717
lines changed

CHANGELOG.md

+18
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
* Audit event scopes containing zero events to save no longer open the audit realm unneccesarily ([PR #7332](https://github.com/realm/realm-core/pull/7332)).
1010
* Added a method to check if a file needs upgrade. ([#7140](https://github.com/realm/realm-core/issues/7140))
1111
* Use `clonefile()` when possible in `File::copy()` on Apple platforms for faster copying. ([PR #7341](https://github.com/realm/realm-core/pull/7341)).
12+
* Introduce the new `SyncUser` interface which can be implemented by SDKs to use sync without the core App Services implementation (or just for greater control over user behavior in tests). ([PR #7300](https://github.com/realm/realm-core/pull/7300).
1213

1314
### Fixed
1415
* Fixed queries like `indexed_property == NONE {x}` which mistakenly matched on only x instead of not x. This only applies when an indexed property with equality (==, or IN) matches with `NONE` on a list of one item. If the constant list contained more than one value then it was working correctly. ([realm-js #7862](https://github.com/realm/realm-java/issues/7862), since v12.5.0)
@@ -20,9 +21,23 @@
2021
* Fixed a crash with `Assertion failed: m_initiated` during sync session startup ([#7074](https://github.com/realm/realm-core/issues/7074), since v10.0.0).
2122
* Fixed a TSAN violation where the user thread could race to read `m_finalized` with the sync event loop ([#6844](https://github.com/realm/realm-core/issues/6844), since v13.15.1)
2223
* Fix a minor race condition when backing up Realm files before a client reset which could have lead to overwriting an existing file. ([PR #7341](https://github.com/realm/realm-core/pull/7341)).
24+
* SyncUser::all_sessions() included sessions in every state *except* for waiting for access token, which was weirdly inconsistent. It now includes all sessions. ([PR #7300](https://github.com/realm/realm-core/pull/7300).
25+
* App::all_users() included logged out users only if they were logged out while the App instance existed. It now always includes all logged out users. ([PR #7300](https://github.com/realm/realm-core/pull/7300).
2326

2427
### Breaking changes
2528
* SyncManager no longer supports reconfiguring after calling reset_for_testing(). SyncManager::configure() has been folded into the constructor, and reset_for_testing() has been renamed to tear_down_for_testing(). ([PR #7351](https://github.com/realm/realm-core/pull/7351))
29+
* The following types have been renamed as part of moving all of the App Services functionality to the app namespace:
30+
- SyncUser -> app::User. Note that there is a new, different type named SyncUser.
31+
- SyncUser::identity -> app::User::user_id. The "identity" word was overloaded to mean two unrelated things, and one has been changed to user_id everywhere.
32+
- SyncUserSubscriptionToken -> app::UserSubscriptionToken
33+
- SyncUserProfile -> app::UserProfile
34+
- App::Config -> AppConfig
35+
- SyncConfig::MetadataMode -> AppConfig::MetadataMode
36+
- MetadataMode::NoMetadata -> MetadataMode::InMemory
37+
([PR #7300](https://github.com/realm/realm-core/pull/7300).
38+
* Some fields have moved from SyncClientConfig to AppConfig. AppConfig now has a SyncClientConfig field rather than it being passed separately to App::get_app(). ([PR #7300](https://github.com/realm/realm-core/pull/7300).
39+
* Sync user management has been removed from SyncManager. This functionality was already additionally available on App. ([PR #7300](https://github.com/realm/realm-core/pull/7300).
40+
* Getting sync sessions from a sync user is now done via SyncManager::get_all_sessions_for() rather than SyncUser::all_sessions(). ([PR #7300](https://github.com/realm/realm-core/pull/7300).
2641

2742
### Compatibility
2843
* Fileformat: Generates files with format v23. Reads and automatically upgrade from fileformat v5.
@@ -37,6 +52,9 @@
3752
* The minimum CMake version has changed from 3.15 to 3.22.1. ([#6537](https://github.com/realm/realm-core/issues/6537))
3853
* Update Catch2 to v3.5.2 ([PR #7297](https://github.com/realm/realm-core/pull/7297)).
3954
* The unused `partition` and `user_local_uuid()` fields have been removed from `FileActionMetadata`. ([PR #7341](https://github.com/realm/realm-core/pull/7341)).
55+
* App metadaa storage has been entirely rewritten in preparation for supporting sharing metadata realms between processes.
56+
* The metadata disabled mode has been replaced with an in-memory metadata mode which performs similarly and doesn't work weirdly differently from the normal mode.
57+
* The ownership relationship between App and User has changed. User now strongly retains App and App has a weak cache of Users.
4058

4159
----------------------------------------------
4260

bindgen/spec.yml

+63-45
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ enums:
221221
- FUNCTION
222222
- API_KEY
223223
MetadataMode:
224-
cppName: SyncClientConfig::MetadataMode
224+
cppName: app::AppConfig::MetadataMode
225225
values:
226226
- NoEncryption
227227
- Encryption
@@ -275,13 +275,18 @@ enums:
275275
- DeleteRealm
276276
- ClientReset
277277
- ClientResetNoRecovery
278+
SyncFileAction:
279+
cppName: SyncFileAction
280+
values:
281+
- DeleteRealm
282+
- BackUpThenDeleteRealm
278283
ProgressDirection:
279284
cppName: SyncSession::ProgressDirection
280285
values:
281286
- upload
282287
- download
283288
SyncUserState:
284-
cppName: SyncUser::State
289+
cppName: UserState
285290
values:
286291
- LoggedOut
287292
- LoggedIn
@@ -434,7 +439,7 @@ records:
434439
default: false
435440

436441
UserIdentity:
437-
cppName: SyncUserIdentity
442+
cppName: app::UserIdentity
438443
fields:
439444
id:
440445
type: std::string
@@ -557,11 +562,6 @@ records:
557562

558563
SyncClientConfig:
559564
fields:
560-
base_file_path: std::string
561-
metadata_mode:
562-
type: MetadataMode
563-
default: MetadataMode::Encryption
564-
custom_encryption_key: std::optional<EncryptionKey>
565565
logger_factory: Nullable<LoggerFactory>
566566
log_level:
567567
type: LoggerLevel
@@ -620,7 +620,7 @@ records:
620620
body: std::string
621621

622622
DeviceInfo:
623-
cppName: app::App::Config::DeviceInfo
623+
cppName: app::AppConfig::DeviceInfo
624624
fields:
625625
platform_version: std::string
626626
sdk_version: std::string
@@ -632,13 +632,19 @@ records:
632632
bundle_id: std::string
633633

634634
AppConfig:
635-
cppName: app::App::Config
635+
cppName: app::AppConfig
636636
fields:
637637
app_id: std::string
638638
transport: SharedGenericNetworkTransport
639639
base_url: std::optional<std::string>
640640
default_request_timeout_ms: std::optional<uint64_t>
641641
device_info: DeviceInfo
642+
base_file_path: std::string
643+
sync_client_config: SyncClientConfig
644+
metadata_mode:
645+
type: MetadataMode
646+
default: MetadataMode::Encryption
647+
custom_encryption_key: std::optional<EncryptionKey>
642648

643649
CompensatingWriteErrorInfo:
644650
cppName: sync::CompensatingWriteErrorInfo
@@ -1132,36 +1138,49 @@ classes:
11321138
provider: AuthProvider
11331139
provider_as_string: std::string
11341140

1135-
SyncUserSubscriptionToken:
1136-
cppName: SyncUser::Token
1141+
UserSubscriptionToken:
1142+
cppName: app::User::Token
11371143

11381144
SyncUser:
11391145
sharedPtrWrapped: SharedSyncUser
11401146
properties:
1141-
all_sessions: std::vector<SharedSyncSession>
11421147
is_logged_in: bool
1143-
identity: const std::string&
1144-
provider_type: const std::string&
1145-
local_identity: const std::string&
1148+
user_id: std::string
1149+
app_id: std::string
1150+
legacy_identities: std::vector<std::string>
11461151
access_token: std::string
11471152
refresh_token: std::string
1153+
state: SyncUserState
1154+
sync_manager: SharedSyncManager
1155+
methods:
1156+
access_token_refresh_required: bool
1157+
request_log_out: '(cb: AsyncCallback<(err: std::optional<AppError>)>&&)'
1158+
request_refresh_user: '(cb: AsyncCallback<(err: std::optional<AppError>)>&&)'
1159+
request_refresh_location: '(cb: AsyncCallback<(err: std::optional<AppError>)>&&)'
1160+
request_access_token: '(cb: AsyncCallback<(err: std::optional<AppError>)>&&)'
1161+
track_realm: '(std::string_view)'
1162+
create_file_action: '(action: SyncFileAction, original_path: std::string_view, requested_recovery_dir: std::optional<std::string>, partition_value: std::string_view) -> std::string'
1163+
1164+
User:
1165+
base: SyncUser
1166+
cppName: app::User
1167+
sharedPtrWrapped: SharedUser
1168+
properties:
1169+
is_anonymous: bool
11481170
device_id: std::string
11491171
has_device_id: bool
11501172
user_profile: UserProfile
11511173
identities: std::vector<UserIdentity>
11521174
custom_data: std::optional<bson::BsonDocument>
1153-
sync_manager: SharedSyncManager
1154-
state: SyncUserState
11551175
subscribers_count: count_t
1176+
app: SharedApp
11561177
methods:
11571178
log_out: ()
1158-
session_for_on_disk_path: '(path: StringData) -> Nullable<SharedSyncSession>'
1159-
subscribe: '(observer: (user: IgnoreArgument<const SyncUser&>)) -> SyncUserSubscriptionToken'
1160-
unsubscribe: '(token: SyncUserSubscriptionToken)'
1161-
# TODO update methods?
1179+
subscribe: '(observer: (user: IgnoreArgument<const app::User&>)) -> UserSubscriptionToken'
1180+
unsubscribe: '(token: UserSubscriptionToken)'
11621181

11631182
UserProfile:
1164-
cppName: SyncUserProfile
1183+
cppName: app::UserProfile
11651184
methods:
11661185
name: '() -> std::optional<std::string>'
11671186
email: '() -> std::optional<std::string>'
@@ -1182,27 +1201,27 @@ classes:
11821201
sharedPtrWrapped: SharedApp
11831202
properties:
11841203
config: const AppConfig&
1185-
current_user: Nullable<SharedSyncUser>
1186-
all_users: std::vector<SharedSyncUser>
1204+
current_user: Nullable<SharedUser>
1205+
all_users: std::vector<SharedUser>
11871206
sync_manager: SharedSyncManager
11881207
subscribers_count: count_t
11891208
staticMethods:
1190-
get_app: '(mode: AppCacheMode, config: AppConfig, sync_client_config: SyncClientConfig) -> SharedApp'
1209+
get_app: '(mode: AppCacheMode, config: const AppConfig&) -> SharedApp'
11911210
get_cached_app: '(app_id: const std::string&) -> SharedApp'
11921211
clear_cached_apps: ()
11931212
close_all_sync_sessions: ()
11941213

11951214
methods:
1196-
log_in_with_credentials: '(credentials: AppCredentials, cb: AsyncCallback<(user: const Nullable<SharedSyncUser>&, err: std::optional<AppError>)>&&)'
1215+
log_in_with_credentials: '(credentials: AppCredentials, cb: AsyncCallback<(user: const Nullable<SharedUser>&, err: std::optional<AppError>)>&&)'
11971216
log_out:
11981217
- '(cb: AsyncCallback<(err: std::optional<AppError>)>&&)'
1199-
- sig: '(user: SharedSyncUser, cb: AsyncCallback<(err: std::optional<AppError>)>&&)'
1218+
- sig: '(user: SharedUser, cb: AsyncCallback<(err: std::optional<AppError>)>&&)'
12001219
suffix: user
1201-
refresh_custom_data: '(user: SharedSyncUser, cb: AsyncCallback<(err: std::optional<AppError>)>&&)'
1202-
link_user: '(user: SharedSyncUser, credentials: const AppCredentials&, cb: AsyncCallback<(user: const Nullable<SharedSyncUser>&, err: std::optional<AppError>)>&&)'
1203-
switch_user: '(user: SharedSyncUser)'
1204-
remove_user: '(user: SharedSyncUser, cb: AsyncCallback<(err: std::optional<AppError>)>&&)'
1205-
delete_user: '(user: SharedSyncUser, cb: AsyncCallback<(err: std::optional<AppError>)>&&)'
1220+
refresh_custom_data: '(user: SharedUser, cb: AsyncCallback<(err: std::optional<AppError>)>&&)'
1221+
link_user: '(user: SharedUser, credentials: const AppCredentials&, cb: AsyncCallback<(user: const Nullable<SharedUser>&, err: std::optional<AppError>)>&&)'
1222+
switch_user: '(user: SharedUser)'
1223+
remove_user: '(user: SharedUser, cb: AsyncCallback<(err: std::optional<AppError>)>&&)'
1224+
delete_user: '(user: SharedUser, cb: AsyncCallback<(err: std::optional<AppError>)>&&)'
12061225
usernamePasswordProviderClient:
12071226
- sig: () -> UsernamePasswordProviderClient
12081227
cppName: provider_client<app::App::UsernamePasswordProviderClient>
@@ -1212,8 +1231,8 @@ classes:
12121231
push_notification_client: '(service_name: const std::string&) -> PushClient'
12131232
subscribe: '(observer: (app: IgnoreArgument<const App&>)) -> AppSubscriptionToken'
12141233
unsubscribe: '(token: AppSubscriptionToken)'
1215-
call_function: '(user: const SharedSyncUser&, name: std::string, args: EJsonArray, service_name: std::optional<std::string>, cb: AsyncCallback<(result: Nullable<const EJson*>, err: std::optional<AppError>)>)'
1216-
make_streaming_request: '(user: SharedSyncUser, name: std::string, args: bson::BsonArray, service_name: std::optional<std::string>) -> Request'
1234+
call_function: '(user: const SharedUser&, name: std::string, args: EJsonArray, service_name: std::optional<std::string>, cb: AsyncCallback<(result: Nullable<const EJson*>, err: std::optional<AppError>)>)'
1235+
make_streaming_request: '(user: SharedUser, name: std::string, args: bson::BsonArray, service_name: std::optional<std::string>) -> Request'
12171236
update_base_url: '(base_url: std::optional<std::string>, cb: AsyncCallback<(err: std::optional<AppError>)>&&)'
12181237
get_base_url: '() const -> std::string'
12191238

@@ -1230,8 +1249,8 @@ classes:
12301249
PushClient:
12311250
cppName: app::PushClient
12321251
methods:
1233-
register_device: '(registration_token: const std::string&, sync_user: const SharedSyncUser&, completion: AsyncCallback<(err: std::optional<AppError>)>&&)'
1234-
deregister_device: '(sync_user: const SharedSyncUser&, completion: AsyncCallback<(err: std::optional<AppError>)>&&)'
1252+
register_device: '(registration_token: const std::string&, sync_user: const SharedUser&, completion: AsyncCallback<(err: std::optional<AppError>)>&&)'
1253+
deregister_device: '(sync_user: const SharedUser&, completion: AsyncCallback<(err: std::optional<AppError>)>&&)'
12351254

12361255
UsernamePasswordProviderClient:
12371256
cppName: app::App::UsernamePasswordProviderClient
@@ -1247,12 +1266,12 @@ classes:
12471266
UserAPIKeyProviderClient:
12481267
cppName: app::App::UserAPIKeyProviderClient
12491268
methods:
1250-
create_api_key: '(name: const std::string&, user: SharedSyncUser, completion: AsyncCallback<(apiKey: UserAPIKey&&, err: std::optional<AppError>)>&&)'
1251-
fetch_api_key: '(id: ObjectId&, user: const SharedSyncUser, completion: AsyncCallback<(apiKey: UserAPIKey&&, err: std::optional<AppError>)>&&)'
1252-
fetch_api_keys: '(user: const SharedSyncUser, completion: AsyncCallback<(apiKeys: std::vector<UserAPIKey>&&, err: std::optional<AppError>)>&&)'
1253-
delete_api_key: '(id: ObjectId&, user: const SharedSyncUser, completion: AsyncCallback<(err: std::optional<AppError>)>&&)'
1254-
enable_api_key: '(id: ObjectId&, user: const SharedSyncUser, completion: AsyncCallback<(err: std::optional<AppError>)>&&)'
1255-
disable_api_key: '(id: ObjectId&, user: const SharedSyncUser, completion: AsyncCallback<(err: std::optional<AppError>)>&&)'
1269+
create_api_key: '(name: const std::string&, user: SharedUser, completion: AsyncCallback<(apiKey: UserAPIKey&&, err: std::optional<AppError>)>&&)'
1270+
fetch_api_key: '(id: ObjectId&, user: const SharedUser, completion: AsyncCallback<(apiKey: UserAPIKey&&, err: std::optional<AppError>)>&&)'
1271+
fetch_api_keys: '(user: const SharedUser, completion: AsyncCallback<(apiKeys: std::vector<UserAPIKey>&&, err: std::optional<AppError>)>&&)'
1272+
delete_api_key: '(id: ObjectId&, user: const SharedUser, completion: AsyncCallback<(err: std::optional<AppError>)>&&)'
1273+
enable_api_key: '(id: ObjectId&, user: const SharedUser, completion: AsyncCallback<(err: std::optional<AppError>)>&&)'
1274+
disable_api_key: '(id: ObjectId&, user: const SharedUser, completion: AsyncCallback<(err: std::optional<AppError>)>&&)'
12561275

12571276
# See Helpers::make_loger_factory to construct one.
12581277
# Using an opaque class here rather than exposing the factory to avoid having to
@@ -1269,16 +1288,15 @@ classes:
12691288
log_level: LoggerLevel
12701289
has_existing_sessions: bool
12711290
methods:
1272-
immediately_run_file_actions: '(original_name: std::string) -> bool'
12731291
set_session_multiplexing: '(allowed: bool)'
12741292
set_log_level: '(level: LoggerLevel)'
12751293
set_logger_factory: '(factory: LoggerFactory)'
12761294
set_user_agent: '(user_agent: std::string)'
12771295
set_timeouts: '(timeouts: SyncClientTimeouts)'
12781296
reconnect: ()
12791297
wait_for_sessions_to_terminate: ()
1280-
path_for_realm: '(config: SyncConfig, custom_file_name: std::optional<std::string>) -> StringData'
12811298
get_existing_active_session: '(path: const std::string&) -> SharedSyncSession'
1299+
get_all_sessions_for: '(user: const SyncUser&) -> std::vector<SharedSyncSession>'
12821300

12831301
ThreadSafeReference: {}
12841302
AsyncOpenTask:

0 commit comments

Comments
 (0)