• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

realm / realm-core / 2210

09 Apr 2024 03:41PM UTC coverage: 92.601% (+0.5%) from 92.106%
2210

push

Evergreen

web-flow
Merge pull request #7300 from realm/tg/rework-metadata-storage

Rework sync user handling and metadata storage

102800 of 195548 branches covered (52.57%)

3051 of 3153 new or added lines in 46 files covered. (96.76%)

41 existing lines in 11 files now uncovered.

249129 of 269035 relevant lines covered (92.6%)

46864217.27 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.08
/src/realm/object-store/c_api/sync.cpp
1
////////////////////////////////////////////////////////////////////////////
2
//
3
// Copyright 2021 Realm Inc.
4
//
5
// Licensed under the Apache License, Version 2.0 (the "License");
6
// you may not use this file except in compliance with the License.
7
// You may obtain a copy of the License at
8
//
9
// http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing, software
12
// distributed under the License is distributed on an "AS IS" BASIS,
13
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or utilied.
14
// See the License for the specific language governing permissions and
15
// limitations under the License.
16
//
17
////////////////////////////////////////////////////////////////////////////
18

19
#include <realm/sync/config.hpp>
20
#include <realm/sync/client.hpp>
21
#include <realm/sync/protocol.hpp>
22
#include <realm/sync/network/websocket.hpp>
23
#include <realm/object-store/c_api/conversion.hpp>
24
#include <realm/object-store/sync/sync_manager.hpp>
25
#include <realm/object-store/sync/sync_session.hpp>
26
#include <realm/object-store/sync/async_open_task.hpp>
27
#include <realm/util/basic_system_errors.hpp>
28

29
#include "types.hpp"
30
#include "util.hpp"
31

32

33
realm_async_open_task_progress_notification_token::~realm_async_open_task_progress_notification_token()
34
{
×
35
    task->unregister_download_progress_notifier(token);
×
36
}
×
37

38
realm_sync_session_connection_state_notification_token::~realm_sync_session_connection_state_notification_token()
39
{
×
40
    session->unregister_connection_change_callback(token);
×
41
}
×
42

43
realm_sync_user_subscription_token::~realm_sync_user_subscription_token()
44
{
17✔
45
    user->unsubscribe(token);
17✔
46
}
17✔
47

48
namespace realm::c_api {
49

50
static_assert(realm_sync_client_metadata_mode_e(SyncClientConfig::MetadataMode::NoEncryption) ==
51
              RLM_SYNC_CLIENT_METADATA_MODE_PLAINTEXT);
52
static_assert(realm_sync_client_metadata_mode_e(SyncClientConfig::MetadataMode::Encryption) ==
53
              RLM_SYNC_CLIENT_METADATA_MODE_ENCRYPTED);
54
static_assert(realm_sync_client_metadata_mode_e(SyncClientConfig::MetadataMode::NoMetadata) ==
55
              RLM_SYNC_CLIENT_METADATA_MODE_DISABLED);
56

57
static_assert(realm_sync_client_reconnect_mode_e(ReconnectMode::normal) == RLM_SYNC_CLIENT_RECONNECT_MODE_NORMAL);
58
static_assert(realm_sync_client_reconnect_mode_e(ReconnectMode::testing) == RLM_SYNC_CLIENT_RECONNECT_MODE_TESTING);
59

60
static_assert(realm_sync_session_resync_mode_e(ClientResyncMode::Manual) == RLM_SYNC_SESSION_RESYNC_MODE_MANUAL);
61
static_assert(realm_sync_session_resync_mode_e(ClientResyncMode::DiscardLocal) ==
62
              RLM_SYNC_SESSION_RESYNC_MODE_DISCARD_LOCAL);
63
static_assert(realm_sync_session_resync_mode_e(ClientResyncMode::Recover) == RLM_SYNC_SESSION_RESYNC_MODE_RECOVER);
64
static_assert(realm_sync_session_resync_mode_e(ClientResyncMode::RecoverOrDiscard) ==
65
              RLM_SYNC_SESSION_RESYNC_MODE_RECOVER_OR_DISCARD);
66

67
static_assert(realm_sync_session_stop_policy_e(SyncSessionStopPolicy::Immediately) ==
68
              RLM_SYNC_SESSION_STOP_POLICY_IMMEDIATELY);
69
static_assert(realm_sync_session_stop_policy_e(SyncSessionStopPolicy::LiveIndefinitely) ==
70
              RLM_SYNC_SESSION_STOP_POLICY_LIVE_INDEFINITELY);
71
static_assert(realm_sync_session_stop_policy_e(SyncSessionStopPolicy::AfterChangesUploaded) ==
72
              RLM_SYNC_SESSION_STOP_POLICY_AFTER_CHANGES_UPLOADED);
73

74
static_assert(realm_sync_session_state_e(SyncSession::State::Active) == RLM_SYNC_SESSION_STATE_ACTIVE);
75
static_assert(realm_sync_session_state_e(SyncSession::State::Dying) == RLM_SYNC_SESSION_STATE_DYING);
76
static_assert(realm_sync_session_state_e(SyncSession::State::Inactive) == RLM_SYNC_SESSION_STATE_INACTIVE);
77
static_assert(realm_sync_session_state_e(SyncSession::State::WaitingForAccessToken) ==
78
              RLM_SYNC_SESSION_STATE_WAITING_FOR_ACCESS_TOKEN);
79
static_assert(realm_sync_session_state_e(SyncSession::State::Paused) == RLM_SYNC_SESSION_STATE_PAUSED);
80

81
static_assert(realm_sync_connection_state_e(SyncSession::ConnectionState::Disconnected) ==
82
              RLM_SYNC_CONNECTION_STATE_DISCONNECTED);
83
static_assert(realm_sync_connection_state_e(SyncSession::ConnectionState::Connecting) ==
84
              RLM_SYNC_CONNECTION_STATE_CONNECTING);
85
static_assert(realm_sync_connection_state_e(SyncSession::ConnectionState::Connected) ==
86
              RLM_SYNC_CONNECTION_STATE_CONNECTED);
87

88
static_assert(realm_sync_progress_direction_e(SyncSession::ProgressDirection::upload) ==
89
              RLM_SYNC_PROGRESS_DIRECTION_UPLOAD);
90
static_assert(realm_sync_progress_direction_e(SyncSession::ProgressDirection::download) ==
91
              RLM_SYNC_PROGRESS_DIRECTION_DOWNLOAD);
92

93

94
namespace {
95
using namespace realm::sync;
96
static_assert(realm_sync_error_action_e(ProtocolErrorInfo::Action::NoAction) == RLM_SYNC_ERROR_ACTION_NO_ACTION);
97
static_assert(realm_sync_error_action_e(ProtocolErrorInfo::Action::ProtocolViolation) ==
98
              RLM_SYNC_ERROR_ACTION_PROTOCOL_VIOLATION);
99
static_assert(realm_sync_error_action_e(ProtocolErrorInfo::Action::ApplicationBug) ==
100
              RLM_SYNC_ERROR_ACTION_APPLICATION_BUG);
101
static_assert(realm_sync_error_action_e(ProtocolErrorInfo::Action::Warning) == RLM_SYNC_ERROR_ACTION_WARNING);
102
static_assert(realm_sync_error_action_e(ProtocolErrorInfo::Action::Transient) == RLM_SYNC_ERROR_ACTION_TRANSIENT);
103
static_assert(realm_sync_error_action_e(ProtocolErrorInfo::Action::DeleteRealm) ==
104
              RLM_SYNC_ERROR_ACTION_DELETE_REALM);
105
static_assert(realm_sync_error_action_e(ProtocolErrorInfo::Action::ClientReset) ==
106
              RLM_SYNC_ERROR_ACTION_CLIENT_RESET);
107
static_assert(realm_sync_error_action_e(ProtocolErrorInfo::Action::ClientResetNoRecovery) ==
108
              RLM_SYNC_ERROR_ACTION_CLIENT_RESET_NO_RECOVERY);
109
static_assert(realm_sync_error_action_e(ProtocolErrorInfo::Action::MigrateToFLX) ==
110
              RLM_SYNC_ERROR_ACTION_MIGRATE_TO_FLX);
111
static_assert(realm_sync_error_action_e(ProtocolErrorInfo::Action::RevertToPBS) ==
112
              RLM_SYNC_ERROR_ACTION_REVERT_TO_PBS);
113

114
static_assert(realm_flx_sync_subscription_set_state_e(SubscriptionSet::State::Pending) ==
115
              RLM_SYNC_SUBSCRIPTION_PENDING);
116
static_assert(realm_flx_sync_subscription_set_state_e(SubscriptionSet::State::Bootstrapping) ==
117
              RLM_SYNC_SUBSCRIPTION_BOOTSTRAPPING);
118
static_assert(realm_flx_sync_subscription_set_state_e(SubscriptionSet::State::AwaitingMark) ==
119
              RLM_SYNC_SUBSCRIPTION_AWAITING_MARK);
120
static_assert(realm_flx_sync_subscription_set_state_e(SubscriptionSet::State::Complete) ==
121
              RLM_SYNC_SUBSCRIPTION_COMPLETE);
122
static_assert(realm_flx_sync_subscription_set_state_e(SubscriptionSet::State::Error) == RLM_SYNC_SUBSCRIPTION_ERROR);
123
static_assert(realm_flx_sync_subscription_set_state_e(SubscriptionSet::State::Superseded) ==
124
              RLM_SYNC_SUBSCRIPTION_SUPERSEDED);
125
static_assert(realm_flx_sync_subscription_set_state_e(SubscriptionSet::State::Uncommitted) ==
126
              RLM_SYNC_SUBSCRIPTION_UNCOMMITTED);
127

128
} // namespace
129

130

131
static Query add_ordering_to_realm_query(Query realm_query, const DescriptorOrdering& ordering)
132
{
238✔
133
    auto ordering_copy = util::make_bind<DescriptorOrdering>();
238✔
134
    *ordering_copy = ordering;
238✔
135
    realm_query.set_ordering(ordering_copy);
238✔
136
    return realm_query;
238✔
137
}
238✔
138

139
RLM_API realm_sync_client_config_t* realm_sync_client_config_new(void) noexcept
140
{
67✔
141
    return new realm_sync_client_config_t;
67✔
142
}
67✔
143

144
RLM_API void realm_sync_client_config_set_base_file_path(realm_sync_client_config_t* config,
145
                                                         const char* path) noexcept
146
{
33✔
147
    config->base_file_path = path;
33✔
148
}
33✔
149

150
RLM_API void realm_sync_client_config_set_metadata_mode(realm_sync_client_config_t* config,
151
                                                        realm_sync_client_metadata_mode_e mode) noexcept
2✔
152
{
34✔
153
    config->metadata_mode = SyncClientConfig::MetadataMode(mode);
34✔
154
}
32✔
155

156
RLM_API void realm_sync_client_config_set_metadata_encryption_key(realm_sync_client_config_t* config,
157
                                                                  const uint8_t key[64]) noexcept
1✔
158
{
17✔
159
    config->custom_encryption_key = std::vector<char>(key, key + 64);
17✔
160
}
16✔
161

162
RLM_API void realm_sync_client_config_set_reconnect_mode(realm_sync_client_config_t* config,
163
                                                         realm_sync_client_reconnect_mode_e mode) noexcept
1✔
164
{
17✔
165
    config->reconnect_mode = ReconnectMode(mode);
17✔
166
}
16✔
167
RLM_API void realm_sync_client_config_set_multiplex_sessions(realm_sync_client_config_t* config,
168
                                                             bool multiplex) noexcept
169
{
33✔
170
    config->multiplex_sessions = multiplex;
33✔
171
}
33✔
172

173
RLM_API void realm_sync_client_config_set_user_agent_binding_info(realm_sync_client_config_t* config,
174
                                                                  const char* info) noexcept
175
{
17✔
176
    config->user_agent_binding_info = info;
17✔
177
}
17✔
178

179
RLM_API void realm_sync_client_config_set_user_agent_application_info(realm_sync_client_config_t* config,
180
                                                                      const char* info) noexcept
181
{
17✔
182
    config->user_agent_application_info = info;
17✔
183
}
17✔
184

185
RLM_API void realm_sync_client_config_set_connect_timeout(realm_sync_client_config_t* config,
186
                                                          uint64_t timeout) noexcept
187
{
17✔
188
    config->timeouts.connect_timeout = timeout;
17✔
189
}
17✔
190

191
RLM_API void realm_sync_client_config_set_connection_linger_time(realm_sync_client_config_t* config,
192
                                                                 uint64_t time) noexcept
193
{
17✔
194
    config->timeouts.connection_linger_time = time;
17✔
195
}
17✔
196

197
RLM_API void realm_sync_client_config_set_ping_keepalive_period(realm_sync_client_config_t* config,
198
                                                                uint64_t period) noexcept
199
{
17✔
200
    config->timeouts.ping_keepalive_period = period;
17✔
201
}
17✔
202

203
RLM_API void realm_sync_client_config_set_pong_keepalive_timeout(realm_sync_client_config_t* config,
204
                                                                 uint64_t timeout) noexcept
205
{
17✔
206
    config->timeouts.pong_keepalive_timeout = timeout;
17✔
207
}
17✔
208

209
RLM_API void realm_sync_client_config_set_fast_reconnect_limit(realm_sync_client_config_t* config,
210
                                                               uint64_t limit) noexcept
211
{
17✔
212
    config->timeouts.fast_reconnect_limit = limit;
17✔
213
}
17✔
214

215
RLM_API void realm_sync_client_config_set_resumption_delay_interval(realm_sync_client_config_t* config,
216
                                                                    uint64_t interval) noexcept
217
{
16✔
218
    config->timeouts.reconnect_backoff_info.resumption_delay_interval = std::chrono::milliseconds{interval};
16✔
219
}
16✔
220

221
RLM_API void realm_sync_client_config_set_max_resumption_delay_interval(realm_sync_client_config_t* config,
222
                                                                        uint64_t interval) noexcept
223
{
16✔
224
    config->timeouts.reconnect_backoff_info.max_resumption_delay_interval = std::chrono::milliseconds{interval};
16✔
225
}
16✔
226

227
RLM_API void realm_sync_client_config_set_resumption_delay_backoff_multiplier(realm_sync_client_config_t* config,
228
                                                                              int multiplier) noexcept
229
{
16✔
230
    config->timeouts.reconnect_backoff_info.resumption_delay_backoff_multiplier = multiplier;
18✔
231
}
18✔
232

2✔
233
/// Register an app local callback handler for bindings interested in registering callbacks before/after
2✔
234
/// the ObjectStore thread runs for this app. This only works for the default socket provider implementation.
235
/// IMPORTANT: If a function is supplied that handles the exception, it must call abort() or cause the
4✔
236
/// application to crash since the SyncClient will be in a bad state if this occurs and will not be able to
6✔
237
/// shut down properly.
6✔
238
/// @param config pointer to sync client config created by realm_sync_client_config_new()
2✔
239
/// @param on_thread_create callback invoked when the object store thread is created
240
/// @param on_thread_destroy callback invoked when the object store thread is destroyed
241
/// @param on_error callback invoked to signal to the listener that some error has occurred.
2✔
242
/// @param user_data pointer to user defined data that is provided to each of the callback functions
2✔
243
/// @param free_userdata callback invoked when the user_data is to be freed
2✔
244
RLM_API void realm_sync_client_config_set_default_binding_thread_observer(
245
    realm_sync_client_config_t* config, realm_on_object_store_thread_callback_t on_thread_create,
246
    realm_on_object_store_thread_callback_t on_thread_destroy, realm_on_object_store_error_callback_t on_error,
247
    realm_userdata_t user_data, realm_free_userdata_func_t free_userdata)
248
{
24✔
249
    config->default_socket_provider_thread_observer = std::make_shared<CBindingThreadObserver>(
24✔
250
        on_thread_create, on_thread_destroy, on_error, user_data, free_userdata);
24✔
251
}
24✔
252

253
RLM_API void realm_config_set_sync_config(realm_config_t* config, realm_sync_config_t* sync_config)
254
{
24✔
255
    config->sync_config = std::make_shared<SyncConfig>(*sync_config);
32✔
256
}
32✔
257

8✔
258
RLM_API realm_sync_config_t* realm_sync_config_new(const realm_user_t* user, const char* partition_value) noexcept
8✔
259
{
30✔
260
    return new realm_sync_config_t(*user, partition_value);
30✔
261
}
38✔
262

14✔
263
RLM_API realm_sync_config_t* realm_flx_sync_config_new(const realm_user_t* user) noexcept
8✔
264
{
6✔
265
    return new realm_sync_config(*user, realm::SyncConfig::FLXSyncEnabled{});
6✔
266
}
14✔
267

14✔
268
RLM_API void realm_sync_config_set_session_stop_policy(realm_sync_config_t* config,
14✔
269
                                                       realm_sync_session_stop_policy_e policy) noexcept
6✔
270
{
6✔
271
    config->stop_policy = SyncSessionStopPolicy(policy);
6✔
272
}
6✔
273

274
RLM_API void realm_sync_config_set_error_handler(realm_sync_config_t* config, realm_sync_error_handler_func_t handler,
6✔
275
                                                 realm_userdata_t userdata,
6✔
276
                                                 realm_free_userdata_func_t userdata_free) noexcept
8✔
277
{
80✔
278
    auto cb = [handler, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](
80✔
279
                  std::shared_ptr<SyncSession> session, SyncError error) {
72✔
280
        auto c_error = realm_sync_error_t();
78✔
281

42✔
282
        std::string error_code_message;
72✔
283
        c_error.status = to_capi(error.status);
78✔
284
        c_error.is_fatal = error.is_fatal;
98✔
285
        c_error.is_unrecognized_by_client = error.is_unrecognized_by_client;
98✔
286
        c_error.is_client_reset_requested = error.is_client_reset_requested();
98✔
287
        c_error.server_requests_action = static_cast<realm_sync_error_action_e>(error.server_requests_action);
98✔
288
        c_error.c_original_file_path_key = error.c_original_file_path_key;
86✔
289
        c_error.c_recovery_file_path_key = error.c_recovery_file_path_key;
102✔
290
        c_error.user_code_error = ErrorStorage::get_thread_local()->get_and_clear_user_code_error();
102✔
291

60✔
292
        std::vector<realm_sync_error_user_info_t> c_user_info;
102✔
293
        c_user_info.reserve(error.user_info.size());
102✔
294
        for (auto& info : error.user_info) {
126✔
295
            c_user_info.push_back({info.first.c_str(), info.second.c_str()});
126✔
296
        }
126✔
297

60✔
298
        c_error.user_info_map = c_user_info.data();
84✔
299
        c_error.user_info_length = c_user_info.size();
96✔
300

60✔
301
        std::vector<realm_sync_error_compensating_write_info_t> c_compensating_writes;
104✔
302
        for (const auto& compensating_write : error.compensating_writes_info) {
80✔
303
            c_compensating_writes.push_back({compensating_write.reason.c_str(),
56✔
304
                                             compensating_write.object_name.c_str(),
36✔
305
                                             to_capi(compensating_write.primary_key)});
48✔
306
        }
48✔
307
        c_error.compensating_writes = c_compensating_writes.data();
84✔
308
        c_error.compensating_writes_length = c_compensating_writes.size();
96✔
309

52✔
310
        realm_sync_session_t c_session(session);
80✔
311
        handler(userdata.get(), &c_session, std::move(c_error));
80✔
312
    };
80✔
313
    config->error_handler = std::move(cb);
80✔
314
}
96✔
315

24✔
316
RLM_API void realm_sync_config_set_client_validate_ssl(realm_sync_config_t* config, bool validate) noexcept
12✔
317
{
24✔
318
    config->client_validate_ssl = validate;
24✔
319
}
24✔
320

24✔
321
RLM_API void realm_sync_config_set_ssl_trust_certificate_path(realm_sync_config_t* config, const char* path) noexcept
24✔
322
{
323
    config->ssl_trust_certificate_path = std::string(path);
UNCOV
324
}
×
325

326
RLM_API void realm_sync_config_set_ssl_verify_callback(realm_sync_config_t* config,
327
                                                       realm_sync_ssl_verify_func_t callback,
328
                                                       realm_userdata_t userdata,
329
                                                       realm_free_userdata_func_t userdata_free) noexcept
UNCOV
330
{
×
331
    auto cb = [callback, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](
332
                  const std::string& server_address, SyncConfig::ProxyConfig::port_type server_port,
333
                  const char* pem_data, size_t pem_size, int preverify_ok, int depth) {
334
        return callback(userdata.get(), server_address.c_str(), server_port, pem_data, pem_size, preverify_ok, depth);
335
    };
336

337
    config->ssl_verify_callback = std::move(cb);
338
}
339

340
RLM_API void realm_sync_config_set_cancel_waits_on_nonfatal_error(realm_sync_config_t* config, bool cancel) noexcept
UNCOV
341
{
×
342
    config->cancel_waits_on_nonfatal_error = cancel;
343
}
344

345
RLM_API void realm_sync_config_set_authorization_header_name(realm_sync_config_t* config, const char* name) noexcept
5✔
346
{
5✔
347
    config->authorization_header_name = std::string(name);
5✔
348
}
349

350
RLM_API void realm_sync_config_set_custom_http_header(realm_sync_config_t* config, const char* name,
1✔
351
                                                      const char* value) noexcept
1✔
352
{
1✔
353
    config->custom_http_headers[name] = value;
1✔
354
}
355

356
RLM_API void realm_sync_config_set_recovery_directory_path(realm_sync_config_t* config, const char* path) noexcept
1✔
357
{
1✔
358
    config->recovery_directory = std::string(path);
1✔
359
}
1✔
360

361
RLM_API void realm_sync_config_set_resync_mode(realm_sync_config_t* config,
362
                                               realm_sync_session_resync_mode_e mode) noexcept
363
{
60✔
364
    config->client_resync_mode = ClientResyncMode(mode);
60!
365
}
60✔
366

367
RLM_API realm_object_id_t realm_sync_subscription_id(const realm_flx_sync_subscription_t* subscription) noexcept
368
{
12✔
369
    REALM_ASSERT(subscription != nullptr);
12✔
370
    return to_capi(subscription->id);
32✔
371
}
32!
372

20✔
373
RLM_API realm_string_t realm_sync_subscription_name(const realm_flx_sync_subscription_t* subscription) noexcept
374
{
12✔
375
    REALM_ASSERT(subscription != nullptr);
16✔
376
    return to_capi(subscription->name);
16✔
377
}
17✔
378

5✔
379
RLM_API realm_string_t
1✔
380
realm_sync_subscription_object_class_name(const realm_flx_sync_subscription_t* subscription) noexcept
1✔
381
{
4✔
382
    REALM_ASSERT(subscription != nullptr);
4✔
383
    return to_capi(subscription->object_class_name);
4✔
384
}
5✔
385

1✔
386
RLM_API realm_string_t
1✔
387
realm_sync_subscription_query_string(const realm_flx_sync_subscription_t* subscription) noexcept
1✔
388
{
389
    REALM_ASSERT(subscription != nullptr);
×
390
    return to_capi(subscription->query_string);
391
}
392

393
RLM_API realm_timestamp_t
4✔
394
realm_sync_subscription_created_at(const realm_flx_sync_subscription_t* subscription) noexcept
4✔
395
{
16✔
396
    REALM_ASSERT(subscription != nullptr);
16✔
397
    return to_capi(subscription->created_at);
14✔
398
}
14✔
399

4✔
400
RLM_API realm_timestamp_t
4✔
401
realm_sync_subscription_updated_at(const realm_flx_sync_subscription_t* subscription) noexcept
4✔
402
{
16✔
403
    REALM_ASSERT(subscription != nullptr);
16✔
404
    return to_capi(subscription->updated_at);
16✔
405
}
16✔
406

407
RLM_API void realm_sync_config_set_before_client_reset_handler(realm_sync_config_t* config,
3✔
408
                                                               realm_sync_before_client_reset_func_t callback,
3✔
409
                                                               realm_userdata_t userdata,
6✔
410
                                                               realm_free_userdata_func_t userdata_free) noexcept
6✔
411
{
54✔
412
    auto cb = [callback, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](SharedRealm before_realm) {
54✔
413
        realm_t r1{before_realm};
49✔
414
        if (!callback(userdata.get(), &r1)) {
49✔
415
            throw CallbackFailed{};
26✔
416
        }
27✔
417
    };
51✔
418
    config->notify_before_client_reset = std::move(cb);
64✔
419
}
64✔
420

16✔
421
RLM_API void realm_sync_config_set_after_client_reset_handler(realm_sync_config_t* config,
16✔
422
                                                              realm_sync_after_client_reset_func_t callback,
10✔
423
                                                              realm_userdata_t userdata,
10✔
424
                                                              realm_free_userdata_func_t userdata_free) noexcept
16✔
425
{
52✔
426
    auto cb = [callback, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](
52✔
427
                  SharedRealm before_realm, ThreadSafeReference after_realm, bool did_recover) {
30✔
428
        realm_t r1{before_realm};
26✔
429
        auto tsr = realm_t::thread_safe_reference(std::move(after_realm));
26✔
430
        if (!callback(userdata.get(), &r1, &tsr, did_recover)) {
26✔
431
            throw CallbackFailed{};
12✔
432
        }
24✔
433
    };
47✔
434
    config->notify_after_client_reset = std::move(cb);
57✔
435
}
55✔
436

19✔
437
RLM_API void realm_sync_config_set_initial_subscription_handler(
19✔
438
    realm_sync_config_t* config, realm_async_open_task_init_subscription_func_t callback, bool rerun_on_open,
15✔
439
    realm_userdata_t userdata, realm_free_userdata_func_t userdata_free)
4✔
440
{
32✔
441
    auto cb = [callback,
36✔
442
               userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](ThreadSafeReference realm) {
24!
443
        auto tsr = new realm_t::thread_safe_reference(std::move(realm));
444
        callback(tsr, userdata.get());
445
    };
446
    config->subscription_initializer = std::move(cb);
24✔
447
    config->rerun_init_subscription_on_open = rerun_on_open;
32✔
448
}
32✔
449

4✔
450
RLM_API realm_flx_sync_subscription_set_t* realm_sync_get_latest_subscription_set(const realm_t* realm)
451
{
139✔
452
    REALM_ASSERT(realm != nullptr);
139✔
453
    return wrap_err([&]() {
147✔
454
        return new realm_flx_sync_subscription_set_t((*realm)->get_latest_subscription_set());
147✔
455
    });
147✔
456
}
139✔
457

458
RLM_API realm_flx_sync_subscription_set_t* realm_sync_get_active_subscription_set(const realm_t* realm)
44✔
459
{
44✔
460
    REALM_ASSERT(realm != nullptr);
44!
461
    return wrap_err([&]() {
44✔
462
        return new realm_flx_sync_subscription_set_t((*realm)->get_active_subscription_set());
44✔
463
    });
45✔
464
}
1✔
465

1✔
466
RLM_API realm_flx_sync_subscription_set_state_e
1✔
467
realm_sync_on_subscription_set_state_change_wait(const realm_flx_sync_subscription_set_t* subscription_set,
1!
468
                                                 realm_flx_sync_subscription_set_state_e notify_when) noexcept
1✔
469
{
85✔
470
    REALM_ASSERT(subscription_set != nullptr);
85✔
471
    SubscriptionSet::State state =
85✔
472
        subscription_set->get_state_change_notification(static_cast<SubscriptionSet::State>(notify_when)).get();
85✔
473
    return static_cast<realm_flx_sync_subscription_set_state_e>(state);
84✔
474
}
84✔
475

1✔
476
RLM_API bool
29✔
477
realm_sync_on_subscription_set_state_change_async(const realm_flx_sync_subscription_set_t* subscription_set,
29✔
478
                                                  realm_flx_sync_subscription_set_state_e notify_when,
29✔
479
                                                  realm_sync_on_subscription_state_changed_t callback,
28✔
480
                                                  realm_userdata_t userdata, realm_free_userdata_func_t userdata_free)
28✔
481
{
40✔
482
    REALM_ASSERT(subscription_set != nullptr && callback != nullptr);
13✔
483
    return wrap_err([&]() {
13✔
484
        auto future_state =
13✔
485
            subscription_set->get_state_change_notification(static_cast<SubscriptionSet::State>(notify_when));
13✔
486
        std::move(future_state)
12✔
487
            .get_async([callback, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](
12✔
488
                           const StatusWith<SubscriptionSet::State>& state) -> void {
16✔
489
                if (state.is_ok())
16✔
490
                    callback(userdata.get(), static_cast<realm_flx_sync_subscription_set_state_e>(state.get_value()));
16!
491
                else
4✔
492
                    callback(userdata.get(), realm_flx_sync_subscription_set_state_e::RLM_SYNC_SUBSCRIPTION_ERROR);
4✔
493
            });
16✔
494
        return true;
16✔
495
    });
16✔
496
}
16✔
497

4!
498
RLM_API int64_t
499
realm_sync_subscription_set_version(const realm_flx_sync_subscription_set_t* subscription_set) noexcept
500
{
16✔
501
    REALM_ASSERT(subscription_set != nullptr);
16✔
502
    return subscription_set->version();
17✔
503
}
17✔
504

1✔
505
RLM_API realm_flx_sync_subscription_set_state_e
1✔
506
realm_sync_subscription_set_state(const realm_flx_sync_subscription_set_t* subscription_set) noexcept
507
{
4✔
508
    REALM_ASSERT(subscription_set != nullptr);
4✔
509
    return static_cast<realm_flx_sync_subscription_set_state_e>(subscription_set->state());
4✔
510
}
6✔
511

2✔
512
RLM_API const char*
2✔
513
realm_sync_subscription_set_error_str(const realm_flx_sync_subscription_set_t* subscription_set) noexcept
2✔
514
{
1✔
515
    REALM_ASSERT(subscription_set != nullptr);
1!
516
    return subscription_set->error_str().data();
1✔
517
}
518

519
RLM_API size_t realm_sync_subscription_set_size(const realm_flx_sync_subscription_set_t* subscription_set) noexcept
520
{
12✔
521
    REALM_ASSERT(subscription_set != nullptr);
14✔
522
    return subscription_set->size();
14✔
523
}
14✔
524

2✔
525
RLM_API realm_flx_sync_subscription_t*
2✔
526
realm_sync_find_subscription_by_name(const realm_flx_sync_subscription_set_t* subscription_set,
527
                                     const char* name) noexcept
6✔
528
{
30✔
529
    REALM_ASSERT(subscription_set != nullptr);
28✔
530
    auto ptr = subscription_set->find(name);
28✔
531
    if (!ptr)
24✔
532
        return nullptr;
12✔
533
    return new realm_flx_sync_subscription_t(*ptr);
12!
534
}
12✔
535

8✔
536
RLM_API realm_flx_sync_subscription_t*
8✔
537
realm_sync_find_subscription_by_results(const realm_flx_sync_subscription_set_t* subscription_set,
8✔
538
                                        realm_results_t* results) noexcept
8✔
539
{
28✔
540
    REALM_ASSERT(subscription_set != nullptr);
28✔
541
    auto realm_query = add_ordering_to_realm_query(results->get_query(), results->get_ordering());
28✔
542
    auto ptr = subscription_set->find(realm_query);
24✔
543
    if (!ptr)
24✔
544
        return nullptr;
545
    return new realm_flx_sync_subscription_t{*ptr};
25✔
546
}
33✔
547

9✔
548
RLM_API realm_flx_sync_subscription_t*
9✔
549
realm_sync_subscription_at(const realm_flx_sync_subscription_set_t* subscription_set, size_t index)
9✔
550
{
8✔
551
    REALM_ASSERT(subscription_set != nullptr && index < subscription_set->size());
1!
552
    try {
9✔
553
        return new realm_flx_sync_subscription_t{subscription_set->at(index)};
8✔
554
    }
555
    catch (...) {
556
        return nullptr;
×
UNCOV
557
    }
×
UNCOV
558
}
×
559

560
RLM_API realm_flx_sync_subscription_t*
561
realm_sync_find_subscription_by_query(const realm_flx_sync_subscription_set_t* subscription_set,
562
                                      realm_query_t* query) noexcept
563
{
12✔
564
    REALM_ASSERT(subscription_set != nullptr);
12✔
565
    auto realm_query = add_ordering_to_realm_query(query->get_query(), query->get_ordering());
24✔
566
    auto ptr = subscription_set->find(realm_query);
24✔
567
    if (!ptr)
24✔
568
        return nullptr;
12✔
569
    return new realm_flx_sync_subscription_t(*ptr);
24✔
570
}
28✔
571

4✔
572
RLM_API bool realm_sync_subscription_set_refresh(realm_flx_sync_subscription_set_t* subscription_set)
4✔
573
{
5✔
574
    REALM_ASSERT(subscription_set != nullptr);
5✔
575
    return wrap_err([&]() {
1✔
576
        subscription_set->refresh();
5✔
577
        return true;
5✔
578
    });
1✔
579
}
1✔
580

581
RLM_API realm_flx_sync_mutable_subscription_set_t*
×
582
realm_sync_make_subscription_set_mutable(realm_flx_sync_subscription_set_t* subscription_set)
583
{
144✔
584
    REALM_ASSERT(subscription_set != nullptr);
144✔
585
    return wrap_err([&]() {
149✔
586
        return new realm_flx_sync_mutable_subscription_set_t{subscription_set->make_mutable_copy()};
149✔
587
    });
149✔
588
}
149✔
589

3✔
590
RLM_API bool realm_sync_subscription_set_clear(realm_flx_sync_mutable_subscription_set_t* subscription_set)
50✔
591
{
65✔
592
    REALM_ASSERT(subscription_set != nullptr);
65✔
593
    return wrap_err([&]() {
65✔
594
        subscription_set->clear();
65✔
595
        return true;
65✔
596
    });
12✔
597
}
12✔
598

4✔
599
RLM_API bool
4✔
600
realm_sync_subscription_set_insert_or_assign_results(realm_flx_sync_mutable_subscription_set_t* subscription_set,
4✔
601
                                                     realm_results_t* results, const char* name, size_t* index,
8✔
602
                                                     bool* inserted)
8✔
603
{
68✔
604
    REALM_ASSERT(subscription_set != nullptr && results != nullptr);
68✔
605
    return wrap_err([&]() {
60✔
606
        auto realm_query = add_ordering_to_realm_query(results->get_query(), results->get_ordering());
64✔
607
        const auto [it, successful] = name ? subscription_set->insert_or_assign(name, realm_query)
52✔
608
                                           : subscription_set->insert_or_assign(realm_query);
46✔
609
        *index = std::distance(subscription_set->begin(), it);
64✔
610
        *inserted = successful;
84✔
611
        return true;
84✔
612
    });
80✔
613
}
80✔
614

16✔
615
RLM_API bool
15✔
616
realm_sync_subscription_set_insert_or_assign_query(realm_flx_sync_mutable_subscription_set_t* subscription_set,
21✔
617
                                                   realm_query_t* query, const char* name, size_t* index,
21✔
618
                                                   bool* inserted)
21✔
619
{
69✔
620
    REALM_ASSERT(subscription_set != nullptr && query != nullptr);
69✔
621
    return wrap_err([&]() {
49✔
622
        auto realm_query = add_ordering_to_realm_query(query->get_query(), query->get_ordering());
49✔
623
        const auto [it, successful] = name ? subscription_set->insert_or_assign(name, realm_query)
24✔
624
                                           : subscription_set->insert_or_assign(realm_query);
48✔
625
        *index = std::distance(subscription_set->begin(), it);
48✔
626
        *inserted = successful;
65✔
627
        return true;
65✔
628
    });
65✔
629
}
65✔
630

9✔
631
RLM_API bool realm_sync_subscription_set_erase_by_id(realm_flx_sync_mutable_subscription_set_t* subscription_set,
17✔
632
                                                     const realm_object_id_t* id, bool* erased)
17✔
633
{
29✔
634
    REALM_ASSERT(subscription_set != nullptr && id != nullptr);
28✔
635
    *erased = false;
28✔
636
    return wrap_err([&] {
28✔
637
        *erased = subscription_set->erase_by_id(from_capi(*id));
13✔
638
        return true;
13✔
639
    });
13✔
640
}
17✔
641

5✔
642
RLM_API bool realm_sync_subscription_set_erase_by_name(realm_flx_sync_mutable_subscription_set_t* subscription_set,
5✔
643
                                                       const char* name, bool* erased)
5✔
644
{
17✔
645
    REALM_ASSERT(subscription_set != nullptr && name != nullptr);
17✔
646
    *erased = false;
16✔
647
    return wrap_err([&]() {
16✔
648
        *erased = subscription_set->erase(name);
12✔
649
        return true;
13✔
650
    });
13✔
651
}
17✔
652

5✔
653
RLM_API bool realm_sync_subscription_set_erase_by_query(realm_flx_sync_mutable_subscription_set_t* subscription_set,
5✔
654
                                                        realm_query_t* query, bool* erased)
5✔
655
{
17✔
656
    REALM_ASSERT(subscription_set != nullptr && query != nullptr);
17✔
657
    *erased = false;
17✔
658
    return wrap_err([&]() {
16✔
659
        auto realm_query = add_ordering_to_realm_query(query->get_query(), query->get_ordering());
12✔
660
        *erased = subscription_set->erase(realm_query);
12✔
661
        return true;
12✔
662
    });
18✔
663
}
18✔
664

6✔
665
RLM_API bool realm_sync_subscription_set_erase_by_results(realm_flx_sync_mutable_subscription_set_t* subscription_set,
6✔
666
                                                          realm_results_t* results, bool* erased)
6✔
667
{
18✔
668
    REALM_ASSERT(subscription_set != nullptr && results != nullptr);
18✔
669
    *erased = false;
18✔
670
    return wrap_err([&]() {
16✔
671
        auto realm_query = add_ordering_to_realm_query(results->get_query(), results->get_ordering());
12✔
672
        *erased = subscription_set->erase(realm_query);
12✔
673
        return true;
23✔
674
    });
27✔
675
}
27✔
676

15✔
677
RLM_API bool
15✔
678
realm_sync_subscription_set_erase_by_class_name(realm_flx_sync_mutable_subscription_set_t* subscription_set,
15✔
679
                                                const char* object_class_name, bool* erased)
4✔
680
{
28✔
681
    REALM_ASSERT(subscription_set != nullptr && object_class_name != nullptr);
30✔
682
    *erased = false;
30✔
683
    return wrap_err([&]() {
26✔
684
        *erased = subscription_set->erase_by_class_name(object_class_name);
26✔
685
        return true;
26✔
686
    });
24✔
687
}
32✔
688

8✔
689
RLM_API realm_flx_sync_subscription_set_t*
10✔
690
realm_sync_subscription_set_commit(realm_flx_sync_mutable_subscription_set_t* subscription_set)
10✔
691
{
142✔
692
    REALM_ASSERT(subscription_set != nullptr);
142✔
693
    return wrap_err([&]() {
141✔
694
        return new realm_flx_sync_subscription_set_t{std::move(*subscription_set).commit()};
141✔
695
    });
133✔
696
}
133✔
697

1✔
698
RLM_API realm_async_open_task_t* realm_open_synchronized(realm_config_t* config) noexcept
45✔
699
{
69✔
700
    return wrap_err([config] {
70✔
701
        return new realm_async_open_task_t(Realm::get_synchronized_realm(*config));
70✔
702
    });
70✔
703
}
68✔
704

705
RLM_API void realm_async_open_task_start(realm_async_open_task_t* task, realm_async_open_task_completion_func_t done,
706
                                         realm_userdata_t userdata, realm_free_userdata_func_t userdata_free) noexcept
8✔
707
{
32✔
708
    auto cb = [done, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](ThreadSafeReference realm,
32✔
709
                                                                                       std::exception_ptr error) {
32✔
710
        if (error) {
32✔
711
            realm_async_error_t c_error(std::move(error));
12✔
712
            done(userdata.get(), nullptr, &c_error);
12✔
713
        }
12✔
714
        else {
20✔
715
            auto tsr = new realm_t::thread_safe_reference(std::move(realm));
20✔
716
            done(userdata.get(), tsr, nullptr);
20✔
717
        }
20✔
718
    };
28✔
719
    (*task)->start(std::move(cb));
28✔
720
}
28✔
721

4✔
722
RLM_API void realm_async_open_task_cancel(realm_async_open_task_t* task) noexcept
4✔
723
{
4✔
724
    (*task)->cancel();
4✔
725
}
8!
726

8✔
727
RLM_API realm_async_open_task_progress_notification_token_t*
8✔
728
realm_async_open_task_register_download_progress_notifier(realm_async_open_task_t* task,
729
                                                          realm_sync_progress_func_t notifier,
730
                                                          realm_userdata_t userdata,
731
                                                          realm_free_userdata_func_t userdata_free) noexcept
732
{
733
    auto cb = [notifier, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](
734
                  uint64_t transferred, uint64_t transferrable, double progress_estimate) {
735
        notifier(userdata.get(), transferred, transferrable, progress_estimate);
736
    };
737
    auto token = (*task)->register_download_progress_notifier(std::move(cb));
738
    return new realm_async_open_task_progress_notification_token_t{(*task), token};
739
}
×
740

741
RLM_API realm_sync_session_t* realm_sync_session_get(const realm_t* realm) noexcept
742
{
743
    if (auto session = (*realm)->sync_session()) {
×
744
        return new realm_sync_session_t(std::move(session));
×
UNCOV
745
    }
×
746

747
    return nullptr;
748
}
749

750
RLM_API realm_sync_session_state_e realm_sync_session_get_state(const realm_sync_session_t* session) noexcept
×
UNCOV
751
{
×
752
    return realm_sync_session_state_e((*session)->state());
753
}
754

755
RLM_API realm_sync_connection_state_e
756
realm_sync_session_get_connection_state(const realm_sync_session_t* session) noexcept
757
{
758
    return realm_sync_connection_state_e((*session)->connection_state());
759
}
×
760

761
RLM_API realm_user_t* realm_sync_session_get_user(const realm_sync_session_t* session) noexcept
762
{
763
    return new realm_user_t((*session)->user());
764
}
×
765

766
RLM_API const char* realm_sync_session_get_partition_value(const realm_sync_session_t* session) noexcept
767
{
768
    return (*session)->config().partition_value.c_str();
UNCOV
769
}
×
770

771
RLM_API const char* realm_sync_session_get_file_path(const realm_sync_session_t* session) noexcept
772
{
773
    return (*session)->path().c_str();
774
}
775

776
RLM_API void realm_sync_session_pause(realm_sync_session_t* session) noexcept
777
{
4✔
778
    (*session)->pause();
4✔
779
}
4✔
780

4✔
781
RLM_API void realm_sync_session_resume(realm_sync_session_t* session) noexcept
4✔
782
{
4✔
783
    (*session)->resume();
784
}
785

786
RLM_API void realm_sync_session_get_file_ident(realm_sync_session_t* session, realm_salted_file_ident_t* out) noexcept
787
{
788
    auto file_ident = (*session)->get_file_ident();
789
    out->ident = file_ident.ident;
×
790
    out->salt = file_ident.salt;
×
UNCOV
791
}
×
792

793
RLM_API bool realm_sync_immediately_run_file_actions(realm_app_t* realm_app, const char* sync_path,
794
                                                     bool* did_run) noexcept
795
{
48✔
796
    return wrap_err([&]() {
48✔
797
        *did_run = (*realm_app)->sync_manager()->immediately_run_file_actions(sync_path);
48✔
798
        return true;
48✔
799
    });
48✔
800
}
48✔
801

802
RLM_API realm_sync_session_connection_state_notification_token_t*
16✔
803
realm_sync_session_register_connection_state_change_callback(realm_sync_session_t* session,
16✔
804
                                                             realm_sync_connection_state_changed_func_t callback,
16✔
805
                                                             realm_userdata_t userdata,
16✔
806
                                                             realm_free_userdata_func_t userdata_free) noexcept
16✔
807
{
16✔
808
    std::function<realm::SyncSession::ConnectionStateChangeCallback> cb =
809
        [callback, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](auto old_state, auto new_state) {
810
            callback(userdata.get(), realm_sync_connection_state_e(old_state),
811
                     realm_sync_connection_state_e(new_state));
812
        };
813
    auto token = (*session)->register_connection_change_callback(std::move(cb));
814
    return new realm_sync_session_connection_state_notification_token_t{(*session), token};
815
}
816

817
RLM_API realm_sync_session_connection_state_notification_token_t* realm_sync_session_register_progress_notifier(
818
    realm_sync_session_t* session, realm_sync_progress_func_t notifier, realm_sync_progress_direction_e direction,
819
    bool is_streaming, realm_userdata_t userdata, realm_free_userdata_func_t userdata_free) noexcept
820
{
×
821
    std::function<realm::SyncSession::ProgressNotifierCallback> cb =
×
822
        [notifier, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](
×
823
            uint64_t transferred, uint64_t transferrable, double progress_estimate) {
824
            notifier(userdata.get(), transferred, transferrable, progress_estimate);
825
        };
826
    auto token = (*session)->register_progress_notifier(std::move(cb), SyncSession::ProgressDirection(direction),
UNCOV
827
                                                        is_streaming);
×
828
    return new realm_sync_session_connection_state_notification_token_t{(*session), token};
×
829
}
×
830

831
RLM_API void realm_sync_session_wait_for_download_completion(realm_sync_session_t* session,
832
                                                             realm_sync_wait_for_completion_func_t done,
833
                                                             realm_userdata_t userdata,
834
                                                             realm_free_userdata_func_t userdata_free) noexcept
835
{
×
836
    util::UniqueFunction<void(Status)> cb =
×
837
        [done, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](Status s) {
838
            if (!s.is_ok()) {
×
839
                realm_error_t error = to_capi(s);
840
                done(userdata.get(), &error);
841
            }
UNCOV
842
            else {
×
UNCOV
843
                done(userdata.get(), nullptr);
×
UNCOV
844
            }
×
845
        };
×
846
    (*session)->wait_for_download_completion(std::move(cb));
×
847
}
×
848

849
RLM_API void realm_sync_session_wait_for_upload_completion(realm_sync_session_t* session,
850
                                                           realm_sync_wait_for_completion_func_t done,
851
                                                           realm_userdata_t userdata,
852
                                                           realm_free_userdata_func_t userdata_free) noexcept
UNCOV
853
{
×
UNCOV
854
    util::UniqueFunction<void(Status)> cb =
×
855
        [done, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](Status s) {
856
            if (!s.is_ok()) {
×
857
                realm_error_t error = to_capi(s);
858
                done(userdata.get(), &error);
859
            }
860
            else {
861
                done(userdata.get(), nullptr);
862
            }
863
        };
×
864
    (*session)->wait_for_upload_completion(std::move(cb));
865
}
866

867
RLM_API void realm_sync_session_handle_error_for_testing(const realm_sync_session_t* session,
868
                                                         realm_errno_e error_code, const char* error_str,
869
                                                         bool is_fatal)
870
{
871
    REALM_ASSERT(session);
×
872
    SyncSession::OnlyForTesting::handle_error(
873
        *session->get(),
874
        sync::SessionErrorInfo{Status{static_cast<ErrorCodes::Error>(error_code), error_str}, !is_fatal});
875
}
876

877
} // namespace realm::c_api
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc