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

realm / realm-core / jonathan.reams_2947

01 Dec 2023 08:08PM UTC coverage: 91.739% (+0.04%) from 91.695%
jonathan.reams_2947

Pull #7160

Evergreen

jbreams
allow handle_error to decide resumability
Pull Request #7160: Prevent resuming a session that has not been fully shut down

92428 of 169414 branches covered (0.0%)

315 of 349 new or added lines in 14 files covered. (90.26%)

80 existing lines in 14 files now uncovered.

232137 of 253041 relevant lines covered (91.74%)

6882826.18 hits per line

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

55.41
/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
namespace realm::c_api {
44

45
static_assert(realm_sync_client_metadata_mode_e(SyncClientConfig::MetadataMode::NoEncryption) ==
46
              RLM_SYNC_CLIENT_METADATA_MODE_PLAINTEXT);
47
static_assert(realm_sync_client_metadata_mode_e(SyncClientConfig::MetadataMode::Encryption) ==
48
              RLM_SYNC_CLIENT_METADATA_MODE_ENCRYPTED);
49
static_assert(realm_sync_client_metadata_mode_e(SyncClientConfig::MetadataMode::NoMetadata) ==
50
              RLM_SYNC_CLIENT_METADATA_MODE_DISABLED);
51

52
static_assert(realm_sync_client_reconnect_mode_e(ReconnectMode::normal) == RLM_SYNC_CLIENT_RECONNECT_MODE_NORMAL);
53
static_assert(realm_sync_client_reconnect_mode_e(ReconnectMode::testing) == RLM_SYNC_CLIENT_RECONNECT_MODE_TESTING);
54

55
static_assert(realm_sync_session_resync_mode_e(ClientResyncMode::Manual) == RLM_SYNC_SESSION_RESYNC_MODE_MANUAL);
56
static_assert(realm_sync_session_resync_mode_e(ClientResyncMode::DiscardLocal) ==
57
              RLM_SYNC_SESSION_RESYNC_MODE_DISCARD_LOCAL);
58
static_assert(realm_sync_session_resync_mode_e(ClientResyncMode::Recover) == RLM_SYNC_SESSION_RESYNC_MODE_RECOVER);
59
static_assert(realm_sync_session_resync_mode_e(ClientResyncMode::RecoverOrDiscard) ==
60
              RLM_SYNC_SESSION_RESYNC_MODE_RECOVER_OR_DISCARD);
61

62
static_assert(realm_sync_session_stop_policy_e(SyncSessionStopPolicy::Immediately) ==
63
              RLM_SYNC_SESSION_STOP_POLICY_IMMEDIATELY);
64
static_assert(realm_sync_session_stop_policy_e(SyncSessionStopPolicy::LiveIndefinitely) ==
65
              RLM_SYNC_SESSION_STOP_POLICY_LIVE_INDEFINITELY);
66
static_assert(realm_sync_session_stop_policy_e(SyncSessionStopPolicy::AfterChangesUploaded) ==
67
              RLM_SYNC_SESSION_STOP_POLICY_AFTER_CHANGES_UPLOADED);
68

69
static_assert(realm_sync_session_state_e(SyncSession::State::Active) == RLM_SYNC_SESSION_STATE_ACTIVE);
70
static_assert(realm_sync_session_state_e(SyncSession::State::Dying) == RLM_SYNC_SESSION_STATE_DYING);
71
static_assert(realm_sync_session_state_e(SyncSession::State::Inactive) == RLM_SYNC_SESSION_STATE_INACTIVE);
72
static_assert(realm_sync_session_state_e(SyncSession::State::WaitingForAccessToken) ==
73
              RLM_SYNC_SESSION_STATE_WAITING_FOR_ACCESS_TOKEN);
74
static_assert(realm_sync_session_state_e(SyncSession::State::Paused) == RLM_SYNC_SESSION_STATE_PAUSED);
75

76
static_assert(realm_sync_connection_state_e(SyncSession::ConnectionState::Disconnected) ==
77
              RLM_SYNC_CONNECTION_STATE_DISCONNECTED);
78
static_assert(realm_sync_connection_state_e(SyncSession::ConnectionState::Connecting) ==
79
              RLM_SYNC_CONNECTION_STATE_CONNECTING);
80
static_assert(realm_sync_connection_state_e(SyncSession::ConnectionState::Connected) ==
81
              RLM_SYNC_CONNECTION_STATE_CONNECTED);
82

83
static_assert(realm_sync_progress_direction_e(SyncSession::ProgressDirection::upload) ==
84
              RLM_SYNC_PROGRESS_DIRECTION_UPLOAD);
85
static_assert(realm_sync_progress_direction_e(SyncSession::ProgressDirection::download) ==
86
              RLM_SYNC_PROGRESS_DIRECTION_DOWNLOAD);
87

88

89
namespace {
90
using namespace realm::sync;
91
static_assert(realm_sync_error_action_e(ProtocolErrorInfo::Action::NoAction) == RLM_SYNC_ERROR_ACTION_NO_ACTION);
92
static_assert(realm_sync_error_action_e(ProtocolErrorInfo::Action::ProtocolViolation) ==
93
              RLM_SYNC_ERROR_ACTION_PROTOCOL_VIOLATION);
94
static_assert(realm_sync_error_action_e(ProtocolErrorInfo::Action::ApplicationBug) ==
95
              RLM_SYNC_ERROR_ACTION_APPLICATION_BUG);
96
static_assert(realm_sync_error_action_e(ProtocolErrorInfo::Action::Warning) == RLM_SYNC_ERROR_ACTION_WARNING);
97
static_assert(realm_sync_error_action_e(ProtocolErrorInfo::Action::Transient) == RLM_SYNC_ERROR_ACTION_TRANSIENT);
98
static_assert(realm_sync_error_action_e(ProtocolErrorInfo::Action::DeleteRealm) ==
99
              RLM_SYNC_ERROR_ACTION_DELETE_REALM);
100
static_assert(realm_sync_error_action_e(ProtocolErrorInfo::Action::ClientReset) ==
101
              RLM_SYNC_ERROR_ACTION_CLIENT_RESET);
102
static_assert(realm_sync_error_action_e(ProtocolErrorInfo::Action::ClientResetNoRecovery) ==
103
              RLM_SYNC_ERROR_ACTION_CLIENT_RESET_NO_RECOVERY);
104
static_assert(realm_sync_error_action_e(ProtocolErrorInfo::Action::MigrateToFLX) ==
105
              RLM_SYNC_ERROR_ACTION_MIGRATE_TO_FLX);
106
static_assert(realm_sync_error_action_e(ProtocolErrorInfo::Action::RevertToPBS) ==
107
              RLM_SYNC_ERROR_ACTION_REVERT_TO_PBS);
108
static_assert(realm_sync_error_action_e(ProtocolErrorInfo::Action::RefreshUser) ==
109
              RLM_SYNC_ERROR_ACTION_REFRESH_USER);
110
static_assert(realm_sync_error_action_e(ProtocolErrorInfo::Action::RefreshLocation) ==
111
              RLM_SYNC_ERROR_ACTION_REFRESH_LOCATION);
112
static_assert(realm_sync_error_action_e(ProtocolErrorInfo::Action::LogOutUser) == RLM_SYNC_ERROR_ACTION_LOG_OUT_USER);
113
static_assert(realm_sync_error_action_e(ProtocolErrorInfo::Action::BackupThenDeleteRealm) ==
114
              RLM_SYNC_ERROR_ACTION_BACKUP_THEN_DELETE_REALM);
115

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

130
} // namespace
131

132

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

141
RLM_API realm_sync_client_config_t* realm_sync_client_config_new(void) noexcept
142
{
4✔
143
    return new realm_sync_client_config_t;
4✔
144
}
4✔
145

146
RLM_API void realm_sync_client_config_set_base_file_path(realm_sync_client_config_t* config,
147
                                                         const char* path) noexcept
148
{
×
149
    config->base_file_path = path;
×
150
}
×
151

152
RLM_API void realm_sync_client_config_set_metadata_mode(realm_sync_client_config_t* config,
153
                                                        realm_sync_client_metadata_mode_e mode) noexcept
154
{
×
155
    config->metadata_mode = SyncClientConfig::MetadataMode(mode);
×
156
}
×
157

158
RLM_API void realm_sync_client_config_set_metadata_encryption_key(realm_sync_client_config_t* config,
159
                                                                  const uint8_t key[64]) noexcept
160
{
×
161
    config->custom_encryption_key = std::vector<char>(key, key + 64);
×
162
}
×
163

164
RLM_API void realm_sync_client_config_set_reconnect_mode(realm_sync_client_config_t* config,
165
                                                         realm_sync_client_reconnect_mode_e mode) noexcept
166
{
×
167
    config->reconnect_mode = ReconnectMode(mode);
×
168
}
×
169
RLM_API void realm_sync_client_config_set_multiplex_sessions(realm_sync_client_config_t* config,
170
                                                             bool multiplex) noexcept
171
{
×
172
    config->multiplex_sessions = multiplex;
×
173
}
×
174

175
RLM_API void realm_sync_client_config_set_user_agent_binding_info(realm_sync_client_config_t* config,
176
                                                                  const char* info) noexcept
177
{
×
178
    config->user_agent_binding_info = info;
×
179
}
×
180

181
RLM_API void realm_sync_client_config_set_user_agent_application_info(realm_sync_client_config_t* config,
182
                                                                      const char* info) noexcept
183
{
×
184
    config->user_agent_application_info = info;
×
185
}
×
186

187
RLM_API void realm_sync_client_config_set_connect_timeout(realm_sync_client_config_t* config,
188
                                                          uint64_t timeout) noexcept
189
{
×
190
    config->timeouts.connect_timeout = timeout;
×
191
}
×
192

193
RLM_API void realm_sync_client_config_set_connection_linger_time(realm_sync_client_config_t* config,
194
                                                                 uint64_t time) noexcept
195
{
×
196
    config->timeouts.connection_linger_time = time;
×
197
}
×
198

199
RLM_API void realm_sync_client_config_set_ping_keepalive_period(realm_sync_client_config_t* config,
200
                                                                uint64_t period) noexcept
201
{
×
202
    config->timeouts.ping_keepalive_period = period;
×
203
}
×
204

205
RLM_API void realm_sync_client_config_set_pong_keepalive_timeout(realm_sync_client_config_t* config,
206
                                                                 uint64_t timeout) noexcept
207
{
×
208
    config->timeouts.pong_keepalive_timeout = timeout;
×
209
}
×
210

211
RLM_API void realm_sync_client_config_set_fast_reconnect_limit(realm_sync_client_config_t* config,
212
                                                               uint64_t limit) noexcept
213
{
×
214
    config->timeouts.fast_reconnect_limit = limit;
×
215
}
×
216

217
/// Register an app local callback handler for bindings interested in registering callbacks before/after
218
/// the ObjectStore thread runs for this app. This only works for the default socket provider implementation.
219
/// IMPORTANT: If a function is supplied that handles the exception, it must call abort() or cause the
220
/// application to crash since the SyncClient will be in a bad state if this occurs and will not be able to
221
/// shut down properly.
222
/// @param config pointer to sync client config created by realm_sync_client_config_new()
223
/// @param on_thread_create callback invoked when the object store thread is created
224
/// @param on_thread_destroy callback invoked when the object store thread is destroyed
225
/// @param on_error callback invoked to signal to the listener that some error has occurred.
226
/// @param user_data pointer to user defined data that is provided to each of the callback functions
227
/// @param free_userdata callback invoked when the user_data is to be freed
228
RLM_API void realm_sync_client_config_set_default_binding_thread_observer(
229
    realm_sync_client_config_t* config, realm_on_object_store_thread_callback_t on_thread_create,
230
    realm_on_object_store_thread_callback_t on_thread_destroy, realm_on_object_store_error_callback_t on_error,
231
    realm_userdata_t user_data, realm_free_userdata_func_t free_userdata)
232
{
4✔
233
    config->default_socket_provider_thread_observer = std::make_shared<CBindingThreadObserver>(
4✔
234
        on_thread_create, on_thread_destroy, on_error, user_data, free_userdata);
4✔
235
}
4✔
236

237
RLM_API void realm_config_set_sync_config(realm_config_t* config, realm_sync_config_t* sync_config)
238
{
4✔
239
    config->sync_config = std::make_shared<SyncConfig>(*sync_config);
4✔
240
}
4✔
241

242
RLM_API realm_sync_config_t* realm_sync_config_new(const realm_user_t* user, const char* partition_value) noexcept
243
{
4✔
244
    return new realm_sync_config_t(*user, partition_value);
4✔
245
}
4✔
246

247
RLM_API realm_sync_config_t* realm_flx_sync_config_new(const realm_user_t* user) noexcept
248
{
×
249
    return new realm_sync_config(*user, realm::SyncConfig::FLXSyncEnabled{});
×
250
}
×
251

252
RLM_API void realm_sync_config_set_session_stop_policy(realm_sync_config_t* config,
253
                                                       realm_sync_session_stop_policy_e policy) noexcept
254
{
×
255
    config->stop_policy = SyncSessionStopPolicy(policy);
×
256
}
×
257

258
RLM_API void realm_sync_config_set_error_handler(realm_sync_config_t* config, realm_sync_error_handler_func_t handler,
259
                                                 realm_userdata_t userdata,
260
                                                 realm_free_userdata_func_t userdata_free) noexcept
261
{
8✔
262
    auto cb = [handler, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](
8✔
263
                  std::shared_ptr<SyncSession> session, SyncError error) {
8✔
264
        auto c_error = realm_sync_error_t();
8✔
265

4✔
266
        std::string error_code_message;
8✔
267
        c_error.status = to_capi(error.status);
8✔
268
        c_error.is_fatal = error.is_fatal;
8✔
269
        c_error.is_unrecognized_by_client = error.is_unrecognized_by_client;
8✔
270
        c_error.is_client_reset_requested = error.is_client_reset_requested();
8✔
271
        c_error.server_requests_action = static_cast<realm_sync_error_action_e>(error.server_requests_action);
8✔
272
        c_error.c_original_file_path_key = error.c_original_file_path_key;
8✔
273
        c_error.c_recovery_file_path_key = error.c_recovery_file_path_key;
8✔
274

4✔
275
        std::vector<realm_sync_error_user_info_t> c_user_info;
8✔
276
        c_user_info.reserve(error.user_info.size());
8✔
277
        for (auto& info : error.user_info) {
8✔
278
            c_user_info.push_back({info.first.c_str(), info.second.c_str()});
8✔
279
        }
8✔
280

4✔
281
        c_error.user_info_map = c_user_info.data();
8✔
282
        c_error.user_info_length = c_user_info.size();
8✔
283

4✔
284
        std::vector<realm_sync_error_compensating_write_info_t> c_compensating_writes;
8✔
285
        for (const auto& compensating_write : error.compensating_writes_info) {
6✔
286
            c_compensating_writes.push_back({compensating_write.reason.c_str(),
4✔
287
                                             compensating_write.object_name.c_str(),
4✔
288
                                             to_capi(compensating_write.primary_key)});
4✔
289
        }
4✔
290
        c_error.compensating_writes = c_compensating_writes.data();
8✔
291
        c_error.compensating_writes_length = c_compensating_writes.size();
8✔
292

4✔
293
        realm_sync_session_t c_session(session);
8✔
294
        handler(userdata.get(), &c_session, std::move(c_error));
8✔
295
    };
8✔
296
    config->error_handler = std::move(cb);
8✔
297
}
8✔
298

299
RLM_API void realm_sync_config_set_client_validate_ssl(realm_sync_config_t* config, bool validate) noexcept
300
{
×
301
    config->client_validate_ssl = validate;
×
302
}
×
303

304
RLM_API void realm_sync_config_set_ssl_trust_certificate_path(realm_sync_config_t* config, const char* path) noexcept
305
{
×
306
    config->ssl_trust_certificate_path = std::string(path);
×
307
}
×
308

309
RLM_API void realm_sync_config_set_ssl_verify_callback(realm_sync_config_t* config,
310
                                                       realm_sync_ssl_verify_func_t callback,
311
                                                       realm_userdata_t userdata,
312
                                                       realm_free_userdata_func_t userdata_free) noexcept
313
{
×
314
    auto cb = [callback, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](
×
315
                  const std::string& server_address, SyncConfig::ProxyConfig::port_type server_port,
×
316
                  const char* pem_data, size_t pem_size, int preverify_ok, int depth) {
×
317
        return callback(userdata.get(), server_address.c_str(), server_port, pem_data, pem_size, preverify_ok, depth);
×
318
    };
×
319

320
    config->ssl_verify_callback = std::move(cb);
×
321
}
×
322

323
RLM_API void realm_sync_config_set_cancel_waits_on_nonfatal_error(realm_sync_config_t* config, bool cancel) noexcept
324
{
×
325
    config->cancel_waits_on_nonfatal_error = cancel;
×
326
}
×
327

328
RLM_API void realm_sync_config_set_authorization_header_name(realm_sync_config_t* config, const char* name) noexcept
329
{
×
330
    config->authorization_header_name = std::string(name);
×
331
}
×
332

333
RLM_API void realm_sync_config_set_custom_http_header(realm_sync_config_t* config, const char* name,
334
                                                      const char* value) noexcept
335
{
×
336
    config->custom_http_headers[name] = value;
×
337
}
×
338

339
RLM_API void realm_sync_config_set_recovery_directory_path(realm_sync_config_t* config, const char* path) noexcept
340
{
×
341
    config->recovery_directory = std::string(path);
×
342
}
×
343

344
RLM_API void realm_sync_config_set_resync_mode(realm_sync_config_t* config,
345
                                               realm_sync_session_resync_mode_e mode) noexcept
346
{
6✔
347
    config->client_resync_mode = ClientResyncMode(mode);
6✔
348
}
6✔
349

350
RLM_API realm_object_id_t realm_sync_subscription_id(const realm_flx_sync_subscription_t* subscription) noexcept
351
{
2✔
352
    REALM_ASSERT(subscription != nullptr);
2✔
353
    return to_capi(subscription->id);
2✔
354
}
2✔
355

356
RLM_API realm_string_t realm_sync_subscription_name(const realm_flx_sync_subscription_t* subscription) noexcept
357
{
2✔
358
    REALM_ASSERT(subscription != nullptr);
2✔
359
    return to_capi(subscription->name);
2✔
360
}
2✔
361

362
RLM_API realm_string_t
363
realm_sync_subscription_object_class_name(const realm_flx_sync_subscription_t* subscription) noexcept
364
{
×
365
    REALM_ASSERT(subscription != nullptr);
×
366
    return to_capi(subscription->object_class_name);
×
367
}
×
368

369
RLM_API realm_string_t
370
realm_sync_subscription_query_string(const realm_flx_sync_subscription_t* subscription) noexcept
371
{
×
372
    REALM_ASSERT(subscription != nullptr);
×
373
    return to_capi(subscription->query_string);
×
374
}
×
375

376
RLM_API realm_timestamp_t
377
realm_sync_subscription_created_at(const realm_flx_sync_subscription_t* subscription) noexcept
378
{
2✔
379
    REALM_ASSERT(subscription != nullptr);
2✔
380
    return to_capi(subscription->created_at);
2✔
381
}
2✔
382

383
RLM_API realm_timestamp_t
384
realm_sync_subscription_updated_at(const realm_flx_sync_subscription_t* subscription) noexcept
385
{
2✔
386
    REALM_ASSERT(subscription != nullptr);
2✔
387
    return to_capi(subscription->updated_at);
2✔
388
}
2✔
389

390
RLM_API void realm_sync_config_set_before_client_reset_handler(realm_sync_config_t* config,
391
                                                               realm_sync_before_client_reset_func_t callback,
392
                                                               realm_userdata_t userdata,
393
                                                               realm_free_userdata_func_t userdata_free) noexcept
394
{
4✔
395
    auto cb = [callback, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](SharedRealm before_realm) {
4✔
396
        realm_t r1{before_realm};
4✔
397
        if (!callback(userdata.get(), &r1)) {
4✔
398
            throw CallbackFailed();
2✔
399
        }
2✔
400
    };
4✔
401
    config->notify_before_client_reset = std::move(cb);
4✔
402
}
4✔
403

404
RLM_API void realm_sync_config_set_after_client_reset_handler(realm_sync_config_t* config,
405
                                                              realm_sync_after_client_reset_func_t callback,
406
                                                              realm_userdata_t userdata,
407
                                                              realm_free_userdata_func_t userdata_free) noexcept
408
{
4✔
409
    auto cb = [callback, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](
4✔
410
                  SharedRealm before_realm, ThreadSafeReference after_realm, bool did_recover) {
3✔
411
        realm_t r1{before_realm};
2✔
412
        auto tsr = realm_t::thread_safe_reference(std::move(after_realm));
2✔
413
        if (!callback(userdata.get(), &r1, &tsr, did_recover)) {
2✔
414
            throw CallbackFailed();
×
415
        }
×
416
    };
2✔
417
    config->notify_after_client_reset = std::move(cb);
4✔
418
}
4✔
419

420
RLM_API void realm_sync_config_set_initial_subscription_handler(
421
    realm_sync_config_t* config, realm_async_open_task_init_subscription_func_t callback, bool rerun_on_open,
422
    realm_userdata_t userdata, realm_free_userdata_func_t userdata_free)
423
{
4✔
424
    auto cb = [callback, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](SharedRealm realm) {
2✔
425
        realm_t r{realm};
×
426
        callback(&r, userdata.get());
×
427
    };
×
428
    config->subscription_initializer = std::move(cb);
4✔
429
    config->rerun_init_subscription_on_open = rerun_on_open;
4✔
430
}
4✔
431

432
RLM_API realm_flx_sync_subscription_set_t* realm_sync_get_latest_subscription_set(const realm_t* realm)
433
{
22✔
434
    REALM_ASSERT(realm != nullptr);
22✔
435
    return wrap_err([&]() {
22✔
436
        return new realm_flx_sync_subscription_set_t((*realm)->get_latest_subscription_set());
22✔
437
    });
22✔
438
}
22✔
439

440
RLM_API realm_flx_sync_subscription_set_t* realm_sync_get_active_subscription_set(const realm_t* realm)
441
{
×
442
    REALM_ASSERT(realm != nullptr);
×
443
    return wrap_err([&]() {
×
444
        return new realm_flx_sync_subscription_set_t((*realm)->get_active_subscription_set());
×
445
    });
×
446
}
×
447

448
RLM_API realm_flx_sync_subscription_set_state_e
449
realm_sync_on_subscription_set_state_change_wait(const realm_flx_sync_subscription_set_t* subscription_set,
450
                                                 realm_flx_sync_subscription_set_state_e notify_when) noexcept
451
{
14✔
452
    REALM_ASSERT(subscription_set != nullptr);
14✔
453
    SubscriptionSet::State state =
14✔
454
        subscription_set->get_state_change_notification(static_cast<SubscriptionSet::State>(notify_when)).get();
14✔
455
    return static_cast<realm_flx_sync_subscription_set_state_e>(state);
14✔
456
}
14✔
457

458
RLM_API bool
459
realm_sync_on_subscription_set_state_change_async(const realm_flx_sync_subscription_set_t* subscription_set,
460
                                                  realm_flx_sync_subscription_set_state_e notify_when,
461
                                                  realm_sync_on_subscription_state_changed_t callback,
462
                                                  realm_userdata_t userdata, realm_free_userdata_func_t userdata_free)
463
{
2✔
464
    REALM_ASSERT(subscription_set != nullptr && callback != nullptr);
2✔
465
    return wrap_err([&]() {
2✔
466
        auto future_state =
2✔
467
            subscription_set->get_state_change_notification(static_cast<SubscriptionSet::State>(notify_when));
2✔
468
        std::move(future_state)
2✔
469
            .get_async([callback, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](
2✔
470
                           const StatusWith<SubscriptionSet::State>& state) -> void {
2✔
471
                if (state.is_ok())
2✔
472
                    callback(userdata.get(), static_cast<realm_flx_sync_subscription_set_state_e>(state.get_value()));
2✔
473
                else
×
474
                    callback(userdata.get(), realm_flx_sync_subscription_set_state_e::RLM_SYNC_SUBSCRIPTION_ERROR);
×
475
            });
2✔
476
        return true;
2✔
477
    });
2✔
478
}
2✔
479

480
RLM_API int64_t
481
realm_sync_subscription_set_version(const realm_flx_sync_subscription_set_t* subscription_set) noexcept
482
{
2✔
483
    REALM_ASSERT(subscription_set != nullptr);
2✔
484
    return subscription_set->version();
2✔
485
}
2✔
486

487
RLM_API realm_flx_sync_subscription_set_state_e
488
realm_sync_subscription_set_state(const realm_flx_sync_subscription_set_t* subscription_set) noexcept
489
{
×
490
    REALM_ASSERT(subscription_set != nullptr);
×
491
    return static_cast<realm_flx_sync_subscription_set_state_e>(subscription_set->state());
×
492
}
×
493

494
RLM_API const char*
495
realm_sync_subscription_set_error_str(const realm_flx_sync_subscription_set_t* subscription_set) noexcept
496
{
×
497
    REALM_ASSERT(subscription_set != nullptr);
×
498
    return subscription_set->error_str().data();
×
499
}
×
500

501
RLM_API size_t realm_sync_subscription_set_size(const realm_flx_sync_subscription_set_t* subscription_set) noexcept
502
{
2✔
503
    REALM_ASSERT(subscription_set != nullptr);
2✔
504
    return subscription_set->size();
2✔
505
}
2✔
506

507
RLM_API realm_flx_sync_subscription_t*
508
realm_sync_find_subscription_by_name(const realm_flx_sync_subscription_set_t* subscription_set,
509
                                     const char* name) noexcept
510
{
4✔
511
    REALM_ASSERT(subscription_set != nullptr);
4✔
512
    auto ptr = subscription_set->find(name);
4✔
513
    if (!ptr)
4✔
514
        return nullptr;
2✔
515
    return new realm_flx_sync_subscription_t(*ptr);
2✔
516
}
2✔
517

518
RLM_API realm_flx_sync_subscription_t*
519
realm_sync_find_subscription_by_results(const realm_flx_sync_subscription_set_t* subscription_set,
520
                                        realm_results_t* results) noexcept
521
{
4✔
522
    REALM_ASSERT(subscription_set != nullptr);
4✔
523
    auto realm_query = add_ordering_to_realm_query(results->get_query(), results->get_ordering());
4✔
524
    auto ptr = subscription_set->find(realm_query);
4✔
525
    if (!ptr)
4✔
526
        return nullptr;
×
527
    return new realm_flx_sync_subscription_t{*ptr};
4✔
528
}
4✔
529

530
RLM_API realm_flx_sync_subscription_t*
531
realm_sync_subscription_at(const realm_flx_sync_subscription_set_t* subscription_set, size_t index)
532
{
×
533
    REALM_ASSERT(subscription_set != nullptr && index < subscription_set->size());
×
534
    try {
×
535
        return new realm_flx_sync_subscription_t{subscription_set->at(index)};
×
536
    }
×
537
    catch (...) {
×
538
        return nullptr;
×
539
    }
×
540
}
×
541

542
RLM_API realm_flx_sync_subscription_t*
543
realm_sync_find_subscription_by_query(const realm_flx_sync_subscription_set_t* subscription_set,
544
                                      realm_query_t* query) noexcept
545
{
2✔
546
    REALM_ASSERT(subscription_set != nullptr);
2✔
547
    auto realm_query = add_ordering_to_realm_query(query->get_query(), query->get_ordering());
2✔
548
    auto ptr = subscription_set->find(realm_query);
2✔
549
    if (!ptr)
2✔
550
        return nullptr;
×
551
    return new realm_flx_sync_subscription_t(*ptr);
2✔
552
}
2✔
553

554
RLM_API bool realm_sync_subscription_set_refresh(realm_flx_sync_subscription_set_t* subscription_set)
555
{
×
556
    REALM_ASSERT(subscription_set != nullptr);
×
557
    return wrap_err([&]() {
×
558
        subscription_set->refresh();
×
559
        return true;
×
560
    });
×
561
}
×
562

563
RLM_API realm_flx_sync_mutable_subscription_set_t*
564
realm_sync_make_subscription_set_mutable(realm_flx_sync_subscription_set_t* subscription_set)
565
{
24✔
566
    REALM_ASSERT(subscription_set != nullptr);
24✔
567
    return wrap_err([&]() {
24✔
568
        return new realm_flx_sync_mutable_subscription_set_t{subscription_set->make_mutable_copy()};
24✔
569
    });
24✔
570
}
24✔
571

572
RLM_API bool realm_sync_subscription_set_clear(realm_flx_sync_mutable_subscription_set_t* subscription_set)
573
{
2✔
574
    REALM_ASSERT(subscription_set != nullptr);
2✔
575
    return wrap_err([&]() {
2✔
576
        subscription_set->clear();
2✔
577
        return true;
2✔
578
    });
2✔
579
}
2✔
580

581
RLM_API bool
582
realm_sync_subscription_set_insert_or_assign_results(realm_flx_sync_mutable_subscription_set_t* subscription_set,
583
                                                     realm_results_t* results, const char* name, size_t* index,
584
                                                     bool* inserted)
585
{
10✔
586
    REALM_ASSERT(subscription_set != nullptr && results != nullptr);
10✔
587
    return wrap_err([&]() {
10✔
588
        auto realm_query = add_ordering_to_realm_query(results->get_query(), results->get_ordering());
10✔
589
        const auto [it, successful] = name ? subscription_set->insert_or_assign(name, realm_query)
8✔
590
                                           : subscription_set->insert_or_assign(realm_query);
7✔
591
        *index = std::distance(subscription_set->begin(), it);
10✔
592
        *inserted = successful;
10✔
593
        return true;
10✔
594
    });
10✔
595
}
10✔
596

597
RLM_API bool
598
realm_sync_subscription_set_insert_or_assign_query(realm_flx_sync_mutable_subscription_set_t* subscription_set,
599
                                                   realm_query_t* query, const char* name, size_t* index,
600
                                                   bool* inserted)
601
{
8✔
602
    REALM_ASSERT(subscription_set != nullptr && query != nullptr);
8✔
603
    return wrap_err([&]() {
8✔
604
        auto realm_query = add_ordering_to_realm_query(query->get_query(), query->get_ordering());
8✔
605
        const auto [it, successful] = name ? subscription_set->insert_or_assign(name, realm_query)
4✔
606
                                           : subscription_set->insert_or_assign(realm_query);
8✔
607
        *index = std::distance(subscription_set->begin(), it);
8✔
608
        *inserted = successful;
8✔
609
        return true;
8✔
610
    });
8✔
611
}
8✔
612

613
RLM_API bool realm_sync_subscription_set_erase_by_id(realm_flx_sync_mutable_subscription_set_t* subscription_set,
614
                                                     const realm_object_id_t* id, bool* erased)
615
{
2✔
616
    REALM_ASSERT(subscription_set != nullptr && id != nullptr);
2✔
617
    *erased = false;
2✔
618
    return wrap_err([&] {
2✔
619
        *erased = subscription_set->erase_by_id(from_capi(*id));
2✔
620
        return true;
2✔
621
    });
2✔
622
}
2✔
623

624
RLM_API bool realm_sync_subscription_set_erase_by_name(realm_flx_sync_mutable_subscription_set_t* subscription_set,
625
                                                       const char* name, bool* erased)
626
{
2✔
627
    REALM_ASSERT(subscription_set != nullptr && name != nullptr);
2✔
628
    *erased = false;
2✔
629
    return wrap_err([&]() {
2✔
630
        *erased = subscription_set->erase(name);
2✔
631
        return true;
2✔
632
    });
2✔
633
}
2✔
634

635
RLM_API bool realm_sync_subscription_set_erase_by_query(realm_flx_sync_mutable_subscription_set_t* subscription_set,
636
                                                        realm_query_t* query, bool* erased)
637
{
2✔
638
    REALM_ASSERT(subscription_set != nullptr && query != nullptr);
2✔
639
    *erased = false;
2✔
640
    return wrap_err([&]() {
2✔
641
        auto realm_query = add_ordering_to_realm_query(query->get_query(), query->get_ordering());
2✔
642
        *erased = subscription_set->erase(realm_query);
2✔
643
        return true;
2✔
644
    });
2✔
645
}
2✔
646

647
RLM_API bool realm_sync_subscription_set_erase_by_results(realm_flx_sync_mutable_subscription_set_t* subscription_set,
648
                                                          realm_results_t* results, bool* erased)
649
{
2✔
650
    REALM_ASSERT(subscription_set != nullptr && results != nullptr);
2✔
651
    *erased = false;
2✔
652
    return wrap_err([&]() {
2✔
653
        auto realm_query = add_ordering_to_realm_query(results->get_query(), results->get_ordering());
2✔
654
        *erased = subscription_set->erase(realm_query);
2✔
655
        return true;
2✔
656
    });
2✔
657
}
2✔
658

659
RLM_API bool
660
realm_sync_subscription_set_erase_by_class_name(realm_flx_sync_mutable_subscription_set_t* subscription_set,
661
                                                const char* object_class_name, bool* erased)
662
{
4✔
663
    REALM_ASSERT(subscription_set != nullptr && object_class_name != nullptr);
4✔
664
    *erased = false;
4✔
665
    return wrap_err([&]() {
4✔
666
        *erased = subscription_set->erase_by_class_name(object_class_name);
4✔
667
        return true;
4✔
668
    });
4✔
669
}
4✔
670

671
RLM_API realm_flx_sync_subscription_set_t*
672
realm_sync_subscription_set_commit(realm_flx_sync_mutable_subscription_set_t* subscription_set)
673
{
22✔
674
    REALM_ASSERT(subscription_set != nullptr);
22✔
675
    return wrap_err([&]() {
22✔
676
        return new realm_flx_sync_subscription_set_t{std::move(*subscription_set).commit()};
22✔
677
    });
22✔
678
}
22✔
679

680
RLM_API realm_async_open_task_t* realm_open_synchronized(realm_config_t* config) noexcept
681
{
4✔
682
    return wrap_err([config] {
4✔
683
        return new realm_async_open_task_t(Realm::get_synchronized_realm(*config));
4✔
684
    });
4✔
685
}
4✔
686

687
RLM_API void realm_async_open_task_start(realm_async_open_task_t* task, realm_async_open_task_completion_func_t done,
688
                                         realm_userdata_t userdata, realm_free_userdata_func_t userdata_free) noexcept
689
{
4✔
690
    auto cb = [done, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](ThreadSafeReference realm,
4✔
691
                                                                                       std::exception_ptr error) {
4✔
692
        if (error) {
4✔
693
            realm_async_error_t c_error(std::move(error));
2✔
694
            done(userdata.get(), nullptr, &c_error);
2✔
695
        }
2✔
696
        else {
2✔
697
            auto tsr = new realm_t::thread_safe_reference(std::move(realm));
2✔
698
            done(userdata.get(), tsr, nullptr);
2✔
699
        }
2✔
700
    };
4✔
701
    (*task)->start(std::move(cb));
4✔
702
}
4✔
703

704
RLM_API void realm_async_open_task_cancel(realm_async_open_task_t* task) noexcept
705
{
×
706
    (*task)->cancel();
×
707
}
×
708

709
RLM_API realm_async_open_task_progress_notification_token_t*
710
realm_async_open_task_register_download_progress_notifier(realm_async_open_task_t* task,
711
                                                          realm_sync_progress_func_t notifier,
712
                                                          realm_userdata_t userdata,
713
                                                          realm_free_userdata_func_t userdata_free) noexcept
714
{
×
715
    auto cb = [notifier, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](uint64_t transferred,
×
716
                                                                                           uint64_t transferrable) {
×
717
        notifier(userdata.get(), transferred, transferrable);
×
718
    };
×
719
    auto token = (*task)->register_download_progress_notifier(std::move(cb));
×
720
    return new realm_async_open_task_progress_notification_token_t{(*task), token};
×
721
}
×
722

723
RLM_API realm_sync_session_t* realm_sync_session_get(const realm_t* realm) noexcept
724
{
×
725
    if (auto session = (*realm)->sync_session()) {
×
726
        return new realm_sync_session_t(std::move(session));
×
727
    }
×
728

729
    return nullptr;
×
730
}
×
731

732
RLM_API realm_sync_session_state_e realm_sync_session_get_state(const realm_sync_session_t* session) noexcept
733
{
×
734
    return realm_sync_session_state_e((*session)->state());
×
735
}
×
736

737
RLM_API realm_sync_connection_state_e
738
realm_sync_session_get_connection_state(const realm_sync_session_t* session) noexcept
739
{
×
740
    return realm_sync_connection_state_e((*session)->connection_state());
×
741
}
×
742

743
RLM_API realm_user_t* realm_sync_session_get_user(const realm_sync_session_t* session) noexcept
744
{
×
745
    return new realm_user_t((*session)->user());
×
746
}
×
747

748
RLM_API const char* realm_sync_session_get_partition_value(const realm_sync_session_t* session) noexcept
749
{
×
750
    return (*session)->config().partition_value.c_str();
×
751
}
×
752

753
RLM_API const char* realm_sync_session_get_file_path(const realm_sync_session_t* session) noexcept
754
{
×
755
    return (*session)->path().c_str();
×
756
}
×
757

758
RLM_API void realm_sync_session_pause(realm_sync_session_t* session) noexcept
759
{
×
760
    (*session)->pause();
×
761
}
×
762

763
RLM_API void realm_sync_session_resume(realm_sync_session_t* session) noexcept
764
{
×
765
    (*session)->resume();
×
766
}
×
767

768
RLM_API bool realm_sync_immediately_run_file_actions(realm_app_t* realm_app, const char* sync_path,
769
                                                     bool* did_run) noexcept
770
{
4✔
771
    return wrap_err([&]() {
4✔
772
        *did_run = (*realm_app)->sync_manager()->immediately_run_file_actions(sync_path);
4✔
773
        return true;
4✔
774
    });
4✔
775
}
4✔
776

777
RLM_API realm_sync_session_connection_state_notification_token_t*
778
realm_sync_session_register_connection_state_change_callback(realm_sync_session_t* session,
779
                                                             realm_sync_connection_state_changed_func_t callback,
780
                                                             realm_userdata_t userdata,
781
                                                             realm_free_userdata_func_t userdata_free) noexcept
782
{
×
783
    std::function<realm::SyncSession::ConnectionStateChangeCallback> cb =
×
784
        [callback, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](auto old_state, auto new_state) {
×
785
            callback(userdata.get(), realm_sync_connection_state_e(old_state),
×
786
                     realm_sync_connection_state_e(new_state));
×
787
        };
×
788
    auto token = (*session)->register_connection_change_callback(std::move(cb));
×
789
    return new realm_sync_session_connection_state_notification_token_t{(*session), token};
×
790
}
×
791

792
RLM_API realm_sync_session_connection_state_notification_token_t* realm_sync_session_register_progress_notifier(
793
    realm_sync_session_t* session, realm_sync_progress_func_t notifier, realm_sync_progress_direction_e direction,
794
    bool is_streaming, realm_userdata_t userdata, realm_free_userdata_func_t userdata_free) noexcept
795
{
×
796
    std::function<realm::SyncSession::ProgressNotifierCallback> cb =
×
797
        [notifier, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](uint64_t transferred,
×
798
                                                                                     uint64_t transferrable) {
×
799
            notifier(userdata.get(), transferred, transferrable);
×
800
        };
×
801
    auto token = (*session)->register_progress_notifier(std::move(cb), SyncSession::ProgressDirection(direction),
×
802
                                                        is_streaming);
×
803
    return new realm_sync_session_connection_state_notification_token_t{(*session), token};
×
804
}
×
805

806
RLM_API void realm_sync_session_wait_for_download_completion(realm_sync_session_t* session,
807
                                                             realm_sync_wait_for_completion_func_t done,
808
                                                             realm_userdata_t userdata,
809
                                                             realm_free_userdata_func_t userdata_free) noexcept
810
{
×
811
    util::UniqueFunction<void(Status)> cb =
×
812
        [done, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](Status s) {
×
813
            if (!s.is_ok()) {
×
814
                realm_error_t error = to_capi(s);
×
815
                done(userdata.get(), &error);
×
816
            }
×
817
            else {
×
818
                done(userdata.get(), nullptr);
×
819
            }
×
820
        };
×
821
    (*session)->wait_for_download_completion(std::move(cb));
×
822
}
×
823

824
RLM_API void realm_sync_session_wait_for_upload_completion(realm_sync_session_t* session,
825
                                                           realm_sync_wait_for_completion_func_t done,
826
                                                           realm_userdata_t userdata,
827
                                                           realm_free_userdata_func_t userdata_free) noexcept
828
{
×
829
    util::UniqueFunction<void(Status)> cb =
×
830
        [done, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](Status s) {
×
831
            if (!s.is_ok()) {
×
832
                realm_error_t error = to_capi(s);
×
833
                done(userdata.get(), &error);
×
834
            }
×
835
            else {
×
836
                done(userdata.get(), nullptr);
×
837
            }
×
838
        };
×
839
    (*session)->wait_for_upload_completion(std::move(cb));
×
840
}
×
841

842
RLM_API void realm_sync_session_handle_error_for_testing(const realm_sync_session_t* session,
843
                                                         realm_errno_e error_code, const char* error_str,
844
                                                         bool is_fatal, realm_sync_error_action_e action)
845
{
×
846
    REALM_ASSERT(session);
×
847
    SyncSession::OnlyForTesting::handle_error(
×
NEW
848
        *session->get(), sync::SessionErrorInfo{Status{static_cast<ErrorCodes::Error>(error_code), error_str},
×
NEW
849
                                                !is_fatal, static_cast<ProtocolErrorInfo::Action>(action)});
×
UNCOV
850
}
×
851

852
} // 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