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

realm / realm-core / 2468

02 Jul 2024 07:51PM UTC coverage: 90.983% (+0.009%) from 90.974%
2468

push

Evergreen

web-flow
[RCORE-2146] CAPI Remove `is_fatal` flag flip (#7751)

102314 of 180446 branches covered (56.7%)

0 of 1 new or added line in 1 file covered. (0.0%)

61 existing lines in 16 files now uncovered.

215154 of 236478 relevant lines covered (90.98%)

5853171.9 hits per line

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

62.1
/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_reconnect_mode_e(ReconnectMode::normal) == RLM_SYNC_CLIENT_RECONNECT_MODE_NORMAL);
46
static_assert(realm_sync_client_reconnect_mode_e(ReconnectMode::testing) == RLM_SYNC_CLIENT_RECONNECT_MODE_TESTING);
47

48
static_assert(realm_sync_session_resync_mode_e(ClientResyncMode::Manual) == RLM_SYNC_SESSION_RESYNC_MODE_MANUAL);
49
static_assert(realm_sync_session_resync_mode_e(ClientResyncMode::DiscardLocal) ==
50
              RLM_SYNC_SESSION_RESYNC_MODE_DISCARD_LOCAL);
51
static_assert(realm_sync_session_resync_mode_e(ClientResyncMode::Recover) == RLM_SYNC_SESSION_RESYNC_MODE_RECOVER);
52
static_assert(realm_sync_session_resync_mode_e(ClientResyncMode::RecoverOrDiscard) ==
53
              RLM_SYNC_SESSION_RESYNC_MODE_RECOVER_OR_DISCARD);
54

55
static_assert(realm_sync_session_stop_policy_e(SyncSessionStopPolicy::Immediately) ==
56
              RLM_SYNC_SESSION_STOP_POLICY_IMMEDIATELY);
57
static_assert(realm_sync_session_stop_policy_e(SyncSessionStopPolicy::LiveIndefinitely) ==
58
              RLM_SYNC_SESSION_STOP_POLICY_LIVE_INDEFINITELY);
59
static_assert(realm_sync_session_stop_policy_e(SyncSessionStopPolicy::AfterChangesUploaded) ==
60
              RLM_SYNC_SESSION_STOP_POLICY_AFTER_CHANGES_UPLOADED);
61

62
static_assert(realm_sync_session_state_e(SyncSession::State::Active) == RLM_SYNC_SESSION_STATE_ACTIVE);
63
static_assert(realm_sync_session_state_e(SyncSession::State::Dying) == RLM_SYNC_SESSION_STATE_DYING);
64
static_assert(realm_sync_session_state_e(SyncSession::State::Inactive) == RLM_SYNC_SESSION_STATE_INACTIVE);
65
static_assert(realm_sync_session_state_e(SyncSession::State::WaitingForAccessToken) ==
66
              RLM_SYNC_SESSION_STATE_WAITING_FOR_ACCESS_TOKEN);
67
static_assert(realm_sync_session_state_e(SyncSession::State::Paused) == RLM_SYNC_SESSION_STATE_PAUSED);
68

69
static_assert(realm_sync_connection_state_e(SyncSession::ConnectionState::Disconnected) ==
70
              RLM_SYNC_CONNECTION_STATE_DISCONNECTED);
71
static_assert(realm_sync_connection_state_e(SyncSession::ConnectionState::Connecting) ==
72
              RLM_SYNC_CONNECTION_STATE_CONNECTING);
73
static_assert(realm_sync_connection_state_e(SyncSession::ConnectionState::Connected) ==
74
              RLM_SYNC_CONNECTION_STATE_CONNECTED);
75

76
static_assert(realm_sync_progress_direction_e(SyncSession::ProgressDirection::upload) ==
77
              RLM_SYNC_PROGRESS_DIRECTION_UPLOAD);
78
static_assert(realm_sync_progress_direction_e(SyncSession::ProgressDirection::download) ==
79
              RLM_SYNC_PROGRESS_DIRECTION_DOWNLOAD);
80

81

82
namespace {
83
using namespace realm::sync;
84
static_assert(realm_sync_error_action_e(ProtocolErrorInfo::Action::NoAction) == RLM_SYNC_ERROR_ACTION_NO_ACTION);
85
static_assert(realm_sync_error_action_e(ProtocolErrorInfo::Action::ProtocolViolation) ==
86
              RLM_SYNC_ERROR_ACTION_PROTOCOL_VIOLATION);
87
static_assert(realm_sync_error_action_e(ProtocolErrorInfo::Action::ApplicationBug) ==
88
              RLM_SYNC_ERROR_ACTION_APPLICATION_BUG);
89
static_assert(realm_sync_error_action_e(ProtocolErrorInfo::Action::Warning) == RLM_SYNC_ERROR_ACTION_WARNING);
90
static_assert(realm_sync_error_action_e(ProtocolErrorInfo::Action::Transient) == RLM_SYNC_ERROR_ACTION_TRANSIENT);
91
static_assert(realm_sync_error_action_e(ProtocolErrorInfo::Action::DeleteRealm) ==
92
              RLM_SYNC_ERROR_ACTION_DELETE_REALM);
93
static_assert(realm_sync_error_action_e(ProtocolErrorInfo::Action::ClientReset) ==
94
              RLM_SYNC_ERROR_ACTION_CLIENT_RESET);
95
static_assert(realm_sync_error_action_e(ProtocolErrorInfo::Action::ClientResetNoRecovery) ==
96
              RLM_SYNC_ERROR_ACTION_CLIENT_RESET_NO_RECOVERY);
97
static_assert(realm_sync_error_action_e(ProtocolErrorInfo::Action::MigrateToFLX) ==
98
              RLM_SYNC_ERROR_ACTION_MIGRATE_TO_FLX);
99
static_assert(realm_sync_error_action_e(ProtocolErrorInfo::Action::RevertToPBS) ==
100
              RLM_SYNC_ERROR_ACTION_REVERT_TO_PBS);
101

102
static_assert(realm_flx_sync_subscription_set_state_e(SubscriptionSet::State::Pending) ==
103
              RLM_SYNC_SUBSCRIPTION_PENDING);
104
static_assert(realm_flx_sync_subscription_set_state_e(SubscriptionSet::State::Bootstrapping) ==
105
              RLM_SYNC_SUBSCRIPTION_BOOTSTRAPPING);
106
static_assert(realm_flx_sync_subscription_set_state_e(SubscriptionSet::State::AwaitingMark) ==
107
              RLM_SYNC_SUBSCRIPTION_AWAITING_MARK);
108
static_assert(realm_flx_sync_subscription_set_state_e(SubscriptionSet::State::Complete) ==
109
              RLM_SYNC_SUBSCRIPTION_COMPLETE);
110
static_assert(realm_flx_sync_subscription_set_state_e(SubscriptionSet::State::Error) == RLM_SYNC_SUBSCRIPTION_ERROR);
111
static_assert(realm_flx_sync_subscription_set_state_e(SubscriptionSet::State::Superseded) ==
112
              RLM_SYNC_SUBSCRIPTION_SUPERSEDED);
113
static_assert(realm_flx_sync_subscription_set_state_e(SubscriptionSet::State::Uncommitted) ==
114
              RLM_SYNC_SUBSCRIPTION_UNCOMMITTED);
115

116
static_assert(realm_sync_file_action(SyncFileAction::DeleteRealm) == RLM_SYNC_FILE_ACTION_DELETE_REALM);
117
static_assert(realm_sync_file_action(SyncFileAction::BackUpThenDeleteRealm) ==
118
              RLM_SYNC_FILE_ACTION_BACK_UP_THEN_DELETE_REALM);
119

120
} // namespace
121

122

123
static Query add_ordering_to_realm_query(Query realm_query, const DescriptorOrdering& ordering)
124
{
28✔
125
    auto ordering_copy = util::make_bind<DescriptorOrdering>();
28✔
126
    *ordering_copy = ordering;
28✔
127
    realm_query.set_ordering(ordering_copy);
28✔
128
    return realm_query;
28✔
129
}
28✔
130

131
RLM_API realm_sync_client_config_t* realm_sync_client_config_new(void) noexcept
132
{
6✔
133
    return new realm_sync_client_config_t;
6✔
134
}
6✔
135

136
RLM_API void realm_sync_client_config_set_reconnect_mode(realm_sync_client_config_t* config,
137
                                                         realm_sync_client_reconnect_mode_e mode) noexcept
138
{
2✔
139
    config->reconnect_mode = ReconnectMode(mode);
2✔
140
}
2✔
141
RLM_API void realm_sync_client_config_set_multiplex_sessions(realm_sync_client_config_t* config,
142
                                                             bool multiplex) noexcept
143
{
4✔
144
    config->multiplex_sessions = multiplex;
4✔
145
}
4✔
146

147
RLM_API void realm_sync_client_config_set_user_agent_binding_info(realm_sync_client_config_t* config,
148
                                                                  const char* info) noexcept
149
{
2✔
150
    config->user_agent_binding_info = info;
2✔
151
}
2✔
152

153
RLM_API void realm_sync_client_config_set_user_agent_application_info(realm_sync_client_config_t* config,
154
                                                                      const char* info) noexcept
155
{
2✔
156
    config->user_agent_application_info = info;
2✔
157
}
2✔
158

159
RLM_API void realm_sync_client_config_set_connect_timeout(realm_sync_client_config_t* config,
160
                                                          uint64_t timeout) noexcept
161
{
2✔
162
    config->timeouts.connect_timeout = timeout;
2✔
163
}
2✔
164

165
RLM_API void realm_sync_client_config_set_connection_linger_time(realm_sync_client_config_t* config,
166
                                                                 uint64_t time) noexcept
167
{
2✔
168
    config->timeouts.connection_linger_time = time;
2✔
169
}
2✔
170

171
RLM_API void realm_sync_client_config_set_ping_keepalive_period(realm_sync_client_config_t* config,
172
                                                                uint64_t period) noexcept
173
{
2✔
174
    config->timeouts.ping_keepalive_period = period;
2✔
175
}
2✔
176

177
RLM_API void realm_sync_client_config_set_pong_keepalive_timeout(realm_sync_client_config_t* config,
178
                                                                 uint64_t timeout) noexcept
179
{
2✔
180
    config->timeouts.pong_keepalive_timeout = timeout;
2✔
181
}
2✔
182

183
RLM_API void realm_sync_client_config_set_fast_reconnect_limit(realm_sync_client_config_t* config,
184
                                                               uint64_t limit) noexcept
185
{
2✔
186
    config->timeouts.fast_reconnect_limit = limit;
2✔
187
}
2✔
188

189
RLM_API void realm_sync_client_config_set_resumption_delay_interval(realm_sync_client_config_t* config,
190
                                                                    uint64_t interval) noexcept
191
{
2✔
192
    config->timeouts.reconnect_backoff_info.resumption_delay_interval = std::chrono::milliseconds{interval};
2✔
193
}
2✔
194

195
RLM_API void realm_sync_client_config_set_max_resumption_delay_interval(realm_sync_client_config_t* config,
196
                                                                        uint64_t interval) noexcept
197
{
2✔
198
    config->timeouts.reconnect_backoff_info.max_resumption_delay_interval = std::chrono::milliseconds{interval};
2✔
199
}
2✔
200

201
RLM_API void realm_sync_client_config_set_resumption_delay_backoff_multiplier(realm_sync_client_config_t* config,
202
                                                                              int multiplier) noexcept
203
{
2✔
204
    config->timeouts.reconnect_backoff_info.resumption_delay_backoff_multiplier = multiplier;
2✔
205
}
2✔
206

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

227
RLM_API void realm_config_set_sync_config(realm_config_t* config, realm_sync_config_t* sync_config)
228
{
4✔
229
    config->sync_config = std::make_shared<SyncConfig>(*sync_config);
4✔
230
}
4✔
231

232
RLM_API realm_sync_config_t* realm_sync_config_new(const realm_user_t* user, const char* partition_value) noexcept
233
{
4✔
234
    return new realm_sync_config_t(*user, partition_value);
4✔
235
}
4✔
236

237
RLM_API realm_sync_config_t* realm_flx_sync_config_new(const realm_user_t* user) noexcept
238
{
×
239
    return new realm_sync_config(*user, realm::SyncConfig::FLXSyncEnabled{});
×
240
}
×
241

242
RLM_API void realm_sync_config_set_session_stop_policy(realm_sync_config_t* config,
243
                                                       realm_sync_session_stop_policy_e policy) noexcept
244
{
×
245
    config->stop_policy = SyncSessionStopPolicy(policy);
×
246
}
×
247

248
RLM_API void realm_sync_config_set_error_handler(realm_sync_config_t* config, realm_sync_error_handler_func_t handler,
249
                                                 realm_userdata_t userdata,
250
                                                 realm_free_userdata_func_t userdata_free) noexcept
251
{
12✔
252
    auto cb = [handler, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](
12✔
253
                  std::shared_ptr<SyncSession> session, SyncError error) {
12✔
254
        auto c_error = realm_sync_error_t();
12✔
255

256
        std::string error_code_message;
12✔
257
        c_error.status = to_capi(error.status);
12✔
258
        c_error.is_fatal = error.is_fatal;
12✔
259
        c_error.is_unrecognized_by_client = error.is_unrecognized_by_client;
12✔
260
        c_error.is_client_reset_requested = error.is_client_reset_requested();
12✔
261
        c_error.server_requests_action = static_cast<realm_sync_error_action_e>(error.server_requests_action);
12✔
262
        c_error.c_original_file_path_key = error.c_original_file_path_key;
12✔
263
        c_error.c_recovery_file_path_key = error.c_recovery_file_path_key;
12✔
264
        c_error.user_code_error = ErrorStorage::get_thread_local()->get_and_clear_user_code_error();
12✔
265

266
        std::vector<realm_sync_error_user_info_t> c_user_info;
12✔
267
        c_user_info.reserve(error.user_info.size());
12✔
268
        for (auto& info : error.user_info) {
16✔
269
            c_user_info.push_back({info.first.c_str(), info.second.c_str()});
16✔
270
        }
16✔
271

272
        c_error.user_info_map = c_user_info.data();
12✔
273
        c_error.user_info_length = c_user_info.size();
12✔
274

275
        std::vector<realm_sync_error_compensating_write_info_t> c_compensating_writes;
12✔
276
        for (const auto& compensating_write : error.compensating_writes_info) {
12✔
277
            c_compensating_writes.push_back({compensating_write.reason.c_str(),
4✔
278
                                             compensating_write.object_name.c_str(),
4✔
279
                                             to_capi(compensating_write.primary_key)});
4✔
280
        }
4✔
281
        c_error.compensating_writes = c_compensating_writes.data();
12✔
282
        c_error.compensating_writes_length = c_compensating_writes.size();
12✔
283

284
        realm_sync_session_t c_session(session);
12✔
285
        handler(userdata.get(), &c_session, std::move(c_error));
12✔
286
    };
12✔
287
    config->error_handler = std::move(cb);
12✔
288
}
12✔
289

290
RLM_API void realm_sync_config_set_client_validate_ssl(realm_sync_config_t* config, bool validate) noexcept
291
{
×
292
    config->client_validate_ssl = validate;
×
293
}
×
294

295
RLM_API void realm_sync_config_set_ssl_trust_certificate_path(realm_sync_config_t* config, const char* path) noexcept
296
{
×
297
    config->ssl_trust_certificate_path = std::string(path);
×
298
}
×
299

300
RLM_API void realm_sync_config_set_ssl_verify_callback(realm_sync_config_t* config,
301
                                                       realm_sync_ssl_verify_func_t callback,
302
                                                       realm_userdata_t userdata,
303
                                                       realm_free_userdata_func_t userdata_free) noexcept
304
{
×
305
    auto cb = [callback, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](
×
306
                  const std::string& server_address, SyncConfig::ProxyConfig::port_type server_port,
×
307
                  const char* pem_data, size_t pem_size, int preverify_ok, int depth) {
×
308
        return callback(userdata.get(), server_address.c_str(), server_port, pem_data, pem_size, preverify_ok, depth);
×
309
    };
×
310

311
    config->ssl_verify_callback = std::move(cb);
×
312
}
×
313

314
RLM_API void realm_sync_config_set_cancel_waits_on_nonfatal_error(realm_sync_config_t* config, bool cancel) noexcept
315
{
×
316
    config->cancel_waits_on_nonfatal_error = cancel;
×
317
}
×
318

319
RLM_API void realm_sync_config_set_authorization_header_name(realm_sync_config_t* config, const char* name) noexcept
320
{
×
321
    config->authorization_header_name = std::string(name);
×
322
}
×
323

324
RLM_API void realm_sync_config_set_custom_http_header(realm_sync_config_t* config, const char* name,
325
                                                      const char* value) noexcept
326
{
×
327
    config->custom_http_headers[name] = value;
×
328
}
×
329

330
RLM_API void realm_sync_config_set_recovery_directory_path(realm_sync_config_t* config, const char* path) noexcept
331
{
×
332
    config->recovery_directory = std::string(path);
×
333
}
×
334

335
RLM_API void realm_sync_config_set_resync_mode(realm_sync_config_t* config,
336
                                               realm_sync_session_resync_mode_e mode) noexcept
337
{
10✔
338
    config->client_resync_mode = ClientResyncMode(mode);
10✔
339
}
10✔
340

341
RLM_API realm_object_id_t realm_sync_subscription_id(const realm_flx_sync_subscription_t* subscription) noexcept
342
{
2✔
343
    REALM_ASSERT(subscription != nullptr);
2✔
344
    return to_capi(subscription->id);
2✔
345
}
2✔
346

347
RLM_API realm_string_t realm_sync_subscription_name(const realm_flx_sync_subscription_t* subscription) noexcept
348
{
2✔
349
    REALM_ASSERT(subscription != nullptr);
2✔
350
    return to_capi(subscription->name);
2✔
351
}
2✔
352

353
RLM_API realm_string_t
354
realm_sync_subscription_object_class_name(const realm_flx_sync_subscription_t* subscription) noexcept
355
{
×
356
    REALM_ASSERT(subscription != nullptr);
×
357
    return to_capi(subscription->object_class_name);
×
358
}
×
359

360
RLM_API realm_string_t
361
realm_sync_subscription_query_string(const realm_flx_sync_subscription_t* subscription) noexcept
362
{
×
363
    REALM_ASSERT(subscription != nullptr);
×
364
    return to_capi(subscription->query_string);
×
365
}
×
366

367
RLM_API realm_timestamp_t
368
realm_sync_subscription_created_at(const realm_flx_sync_subscription_t* subscription) noexcept
369
{
2✔
370
    REALM_ASSERT(subscription != nullptr);
2✔
371
    return to_capi(subscription->created_at);
2✔
372
}
2✔
373

374
RLM_API realm_timestamp_t
375
realm_sync_subscription_updated_at(const realm_flx_sync_subscription_t* subscription) noexcept
376
{
2✔
377
    REALM_ASSERT(subscription != nullptr);
2✔
378
    return to_capi(subscription->updated_at);
2✔
379
}
2✔
380

381
RLM_API void realm_sync_config_set_before_client_reset_handler(realm_sync_config_t* config,
382
                                                               realm_sync_before_client_reset_func_t callback,
383
                                                               realm_userdata_t userdata,
384
                                                               realm_free_userdata_func_t userdata_free) noexcept
385
{
8✔
386
    auto cb = [callback, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](SharedRealm before_realm) {
8✔
387
        realm_t r1{before_realm};
8✔
388
        if (!callback(userdata.get(), &r1)) {
8✔
389
            throw CallbackFailed{};
4✔
390
        }
4✔
391
    };
8✔
392
    config->notify_before_client_reset = std::move(cb);
8✔
393
}
8✔
394

395
RLM_API void realm_sync_config_set_after_client_reset_handler(realm_sync_config_t* config,
396
                                                              realm_sync_after_client_reset_func_t callback,
397
                                                              realm_userdata_t userdata,
398
                                                              realm_free_userdata_func_t userdata_free) noexcept
399
{
6✔
400
    auto cb = [callback, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](
6✔
401
                  SharedRealm before_realm, ThreadSafeReference after_realm, bool did_recover) {
6✔
402
        realm_t r1{before_realm};
4✔
403
        auto tsr = realm_t::thread_safe_reference(std::move(after_realm));
4✔
404
        if (!callback(userdata.get(), &r1, &tsr, did_recover)) {
4✔
405
            throw CallbackFailed{};
2✔
406
        }
2✔
407
    };
4✔
408
    config->notify_after_client_reset = std::move(cb);
6✔
409
}
6✔
410

411
RLM_API void realm_sync_config_set_initial_subscription_handler(
412
    realm_sync_config_t* config, realm_async_open_task_init_subscription_func_t callback, bool rerun_on_open,
413
    realm_userdata_t userdata, realm_free_userdata_func_t userdata_free)
414
{
4✔
415
    auto cb = [callback,
4✔
416
               userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](ThreadSafeReference realm) {
4✔
417
        auto tsr = new realm_t::thread_safe_reference(std::move(realm));
×
418
        callback(tsr, userdata.get());
×
419
    };
×
420
    config->subscription_initializer = std::move(cb);
4✔
421
    config->rerun_init_subscription_on_open = rerun_on_open;
4✔
422
}
4✔
423

424
RLM_API realm_flx_sync_subscription_set_t* realm_sync_get_latest_subscription_set(const realm_t* realm)
425
{
22✔
426
    REALM_ASSERT(realm != nullptr);
22✔
427
    return wrap_err([&]() {
22✔
428
        return new realm_flx_sync_subscription_set_t((*realm)->get_latest_subscription_set());
22✔
429
    });
22✔
430
}
22✔
431

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

440
RLM_API realm_flx_sync_subscription_set_state_e
441
realm_sync_on_subscription_set_state_change_wait(const realm_flx_sync_subscription_set_t* subscription_set,
442
                                                 realm_flx_sync_subscription_set_state_e notify_when) noexcept
443
{
14✔
444
    REALM_ASSERT(subscription_set != nullptr);
14✔
445
    SubscriptionSet::State state =
14✔
446
        subscription_set->get_state_change_notification(static_cast<SubscriptionSet::State>(notify_when)).get();
14✔
447
    return static_cast<realm_flx_sync_subscription_set_state_e>(state);
14✔
448
}
14✔
449

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

472
RLM_API int64_t
473
realm_sync_subscription_set_version(const realm_flx_sync_subscription_set_t* subscription_set) noexcept
474
{
2✔
475
    REALM_ASSERT(subscription_set != nullptr);
2✔
476
    return subscription_set->version();
2✔
477
}
2✔
478

479
RLM_API realm_flx_sync_subscription_set_state_e
480
realm_sync_subscription_set_state(const realm_flx_sync_subscription_set_t* subscription_set) noexcept
481
{
×
482
    REALM_ASSERT(subscription_set != nullptr);
×
483
    return static_cast<realm_flx_sync_subscription_set_state_e>(subscription_set->state());
×
484
}
×
485

486
RLM_API const char*
487
realm_sync_subscription_set_error_str(const realm_flx_sync_subscription_set_t* subscription_set) noexcept
488
{
×
489
    REALM_ASSERT(subscription_set != nullptr);
×
490
    return subscription_set->error_str().data();
×
491
}
×
492

493
RLM_API size_t realm_sync_subscription_set_size(const realm_flx_sync_subscription_set_t* subscription_set) noexcept
494
{
2✔
495
    REALM_ASSERT(subscription_set != nullptr);
2✔
496
    return subscription_set->size();
2✔
497
}
2✔
498

499
RLM_API realm_flx_sync_subscription_t*
500
realm_sync_find_subscription_by_name(const realm_flx_sync_subscription_set_t* subscription_set,
501
                                     const char* name) noexcept
502
{
4✔
503
    REALM_ASSERT(subscription_set != nullptr);
4✔
504
    auto ptr = subscription_set->find(name);
4✔
505
    if (!ptr)
4✔
506
        return nullptr;
2✔
507
    return new realm_flx_sync_subscription_t(*ptr);
2✔
508
}
4✔
509

510
RLM_API realm_flx_sync_subscription_t*
511
realm_sync_find_subscription_by_results(const realm_flx_sync_subscription_set_t* subscription_set,
512
                                        realm_results_t* results) noexcept
513
{
4✔
514
    REALM_ASSERT(subscription_set != nullptr);
4✔
515
    auto realm_query = add_ordering_to_realm_query(results->get_query(), results->get_ordering());
4✔
516
    auto ptr = subscription_set->find(realm_query);
4✔
517
    if (!ptr)
4✔
518
        return nullptr;
×
519
    return new realm_flx_sync_subscription_t{*ptr};
4✔
520
}
4✔
521

522
RLM_API realm_flx_sync_subscription_t*
523
realm_sync_subscription_at(const realm_flx_sync_subscription_set_t* subscription_set, size_t index)
524
{
×
525
    REALM_ASSERT(subscription_set != nullptr && index < subscription_set->size());
×
526
    try {
×
527
        return new realm_flx_sync_subscription_t{subscription_set->at(index)};
×
528
    }
×
529
    catch (...) {
×
530
        return nullptr;
×
531
    }
×
532
}
×
533

534
RLM_API realm_flx_sync_subscription_t*
535
realm_sync_find_subscription_by_query(const realm_flx_sync_subscription_set_t* subscription_set,
536
                                      realm_query_t* query) noexcept
537
{
2✔
538
    REALM_ASSERT(subscription_set != nullptr);
2✔
539
    auto realm_query = add_ordering_to_realm_query(query->get_query(), query->get_ordering());
2✔
540
    auto ptr = subscription_set->find(realm_query);
2✔
541
    if (!ptr)
2✔
542
        return nullptr;
×
543
    return new realm_flx_sync_subscription_t(*ptr);
2✔
544
}
2✔
545

546
RLM_API bool realm_sync_subscription_set_refresh(realm_flx_sync_subscription_set_t* subscription_set)
547
{
×
548
    REALM_ASSERT(subscription_set != nullptr);
×
549
    return wrap_err([&]() {
×
550
        subscription_set->refresh();
×
551
        return true;
×
552
    });
×
553
}
×
554

555
RLM_API realm_flx_sync_mutable_subscription_set_t*
556
realm_sync_make_subscription_set_mutable(realm_flx_sync_subscription_set_t* subscription_set)
557
{
24✔
558
    REALM_ASSERT(subscription_set != nullptr);
24✔
559
    return wrap_err([&]() {
24✔
560
        return new realm_flx_sync_mutable_subscription_set_t{subscription_set->make_mutable_copy()};
24✔
561
    });
24✔
562
}
24✔
563

564
RLM_API bool realm_sync_subscription_set_clear(realm_flx_sync_mutable_subscription_set_t* subscription_set)
565
{
2✔
566
    REALM_ASSERT(subscription_set != nullptr);
2✔
567
    return wrap_err([&]() {
2✔
568
        subscription_set->clear();
2✔
569
        return true;
2✔
570
    });
2✔
571
}
2✔
572

573
RLM_API bool
574
realm_sync_subscription_set_insert_or_assign_results(realm_flx_sync_mutable_subscription_set_t* subscription_set,
575
                                                     realm_results_t* results, const char* name, size_t* index,
576
                                                     bool* inserted)
577
{
10✔
578
    REALM_ASSERT(subscription_set != nullptr && results != nullptr);
10✔
579
    return wrap_err([&]() {
10✔
580
        auto realm_query = add_ordering_to_realm_query(results->get_query(), results->get_ordering());
10✔
581
        const auto [it, successful] = name ? subscription_set->insert_or_assign(name, realm_query)
10✔
582
                                           : subscription_set->insert_or_assign(realm_query);
10✔
583
        *index = std::distance(subscription_set->begin(), it);
10✔
584
        *inserted = successful;
10✔
585
        return true;
10✔
586
    });
10✔
587
}
10✔
588

589
RLM_API bool
590
realm_sync_subscription_set_insert_or_assign_query(realm_flx_sync_mutable_subscription_set_t* subscription_set,
591
                                                   realm_query_t* query, const char* name, size_t* index,
592
                                                   bool* inserted)
593
{
8✔
594
    REALM_ASSERT(subscription_set != nullptr && query != nullptr);
8✔
595
    return wrap_err([&]() {
8✔
596
        auto realm_query = add_ordering_to_realm_query(query->get_query(), query->get_ordering());
8✔
597
        const auto [it, successful] = name ? subscription_set->insert_or_assign(name, realm_query)
8✔
598
                                           : subscription_set->insert_or_assign(realm_query);
8✔
599
        *index = std::distance(subscription_set->begin(), it);
8✔
600
        *inserted = successful;
8✔
601
        return true;
8✔
602
    });
8✔
603
}
8✔
604

605
RLM_API bool realm_sync_subscription_set_erase_by_id(realm_flx_sync_mutable_subscription_set_t* subscription_set,
606
                                                     const realm_object_id_t* id, bool* erased)
607
{
2✔
608
    REALM_ASSERT(subscription_set != nullptr && id != nullptr);
2✔
609
    *erased = false;
2✔
610
    return wrap_err([&] {
2✔
611
        *erased = subscription_set->erase_by_id(from_capi(*id));
2✔
612
        return true;
2✔
613
    });
2✔
614
}
2✔
615

616
RLM_API bool realm_sync_subscription_set_erase_by_name(realm_flx_sync_mutable_subscription_set_t* subscription_set,
617
                                                       const char* name, bool* erased)
618
{
2✔
619
    REALM_ASSERT(subscription_set != nullptr && name != nullptr);
2✔
620
    *erased = false;
2✔
621
    return wrap_err([&]() {
2✔
622
        *erased = subscription_set->erase(name);
2✔
623
        return true;
2✔
624
    });
2✔
625
}
2✔
626

627
RLM_API bool realm_sync_subscription_set_erase_by_query(realm_flx_sync_mutable_subscription_set_t* subscription_set,
628
                                                        realm_query_t* query, bool* erased)
629
{
2✔
630
    REALM_ASSERT(subscription_set != nullptr && query != nullptr);
2✔
631
    *erased = false;
2✔
632
    return wrap_err([&]() {
2✔
633
        auto realm_query = add_ordering_to_realm_query(query->get_query(), query->get_ordering());
2✔
634
        *erased = subscription_set->erase(realm_query);
2✔
635
        return true;
2✔
636
    });
2✔
637
}
2✔
638

639
RLM_API bool realm_sync_subscription_set_erase_by_results(realm_flx_sync_mutable_subscription_set_t* subscription_set,
640
                                                          realm_results_t* results, bool* erased)
641
{
2✔
642
    REALM_ASSERT(subscription_set != nullptr && results != nullptr);
2✔
643
    *erased = false;
2✔
644
    return wrap_err([&]() {
2✔
645
        auto realm_query = add_ordering_to_realm_query(results->get_query(), results->get_ordering());
2✔
646
        *erased = subscription_set->erase(realm_query);
2✔
647
        return true;
2✔
648
    });
2✔
649
}
2✔
650

651
RLM_API bool
652
realm_sync_subscription_set_erase_by_class_name(realm_flx_sync_mutable_subscription_set_t* subscription_set,
653
                                                const char* object_class_name, bool* erased)
654
{
4✔
655
    REALM_ASSERT(subscription_set != nullptr && object_class_name != nullptr);
4✔
656
    *erased = false;
4✔
657
    return wrap_err([&]() {
4✔
658
        *erased = subscription_set->erase_by_class_name(object_class_name);
4✔
659
        return true;
4✔
660
    });
4✔
661
}
4✔
662

663
RLM_API realm_flx_sync_subscription_set_t*
664
realm_sync_subscription_set_commit(realm_flx_sync_mutable_subscription_set_t* subscription_set)
665
{
22✔
666
    REALM_ASSERT(subscription_set != nullptr);
22✔
667
    return wrap_err([&]() {
22✔
668
        return new realm_flx_sync_subscription_set_t{std::move(*subscription_set).commit()};
22✔
669
    });
22✔
670
}
22✔
671

672
RLM_API realm_async_open_task_t* realm_open_synchronized(realm_config_t* config) noexcept
673
{
4✔
674
    return wrap_err([config] {
4✔
675
        return new realm_async_open_task_t(Realm::get_synchronized_realm(*config));
4✔
676
    });
4✔
677
}
4✔
678

679
RLM_API void realm_async_open_task_start(realm_async_open_task_t* task, realm_async_open_task_completion_func_t done,
680
                                         realm_userdata_t userdata, realm_free_userdata_func_t userdata_free) noexcept
681
{
4✔
682
    auto cb = [done, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](ThreadSafeReference realm,
4✔
683
                                                                                       std::exception_ptr error) {
4✔
684
        if (error) {
4✔
685
            realm_async_error_t c_error(std::move(error));
2✔
686
            done(userdata.get(), nullptr, &c_error);
2✔
687
        }
2✔
688
        else {
2✔
689
            auto tsr = new realm_t::thread_safe_reference(std::move(realm));
2✔
690
            done(userdata.get(), tsr, nullptr);
2✔
691
        }
2✔
692
    };
4✔
693
    (*task)->start(std::move(cb));
4✔
694
}
4✔
695

696
RLM_API void realm_async_open_task_cancel(realm_async_open_task_t* task) noexcept
697
{
×
698
    (*task)->cancel();
×
699
}
×
700

701
RLM_API realm_async_open_task_progress_notification_token_t*
702
realm_async_open_task_register_download_progress_notifier(realm_async_open_task_t* task,
703
                                                          realm_sync_progress_func_t notifier,
704
                                                          realm_userdata_t userdata,
705
                                                          realm_free_userdata_func_t userdata_free) noexcept
706
{
×
707
    auto cb = [notifier, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](
×
708
                  uint64_t transferred, uint64_t transferrable, double progress_estimate) {
×
709
        notifier(userdata.get(), transferred, transferrable, progress_estimate);
×
710
    };
×
711
    auto token = (*task)->register_download_progress_notifier(std::move(cb));
×
712
    return new realm_async_open_task_progress_notification_token_t{(*task), token};
×
713
}
×
714

715
RLM_API realm_sync_session_t* realm_sync_session_get(const realm_t* realm) noexcept
716
{
×
717
    if (auto session = (*realm)->sync_session()) {
×
718
        return new realm_sync_session_t(std::move(session));
×
719
    }
×
720

721
    return nullptr;
×
722
}
×
723

724
RLM_API realm_sync_session_state_e realm_sync_session_get_state(const realm_sync_session_t* session) noexcept
725
{
×
726
    return realm_sync_session_state_e((*session)->state());
×
727
}
×
728

729
RLM_API realm_sync_connection_state_e
730
realm_sync_session_get_connection_state(const realm_sync_session_t* session) noexcept
731
{
×
732
    return realm_sync_connection_state_e((*session)->connection_state());
×
733
}
×
734

735
RLM_API realm_user_t* realm_sync_session_get_user(const realm_sync_session_t* session) noexcept
736
{
×
737
    return new realm_user_t((*session)->user());
×
738
}
×
739

740
RLM_API const char* realm_sync_session_get_partition_value(const realm_sync_session_t* session) noexcept
741
{
×
742
    return (*session)->config().partition_value.c_str();
×
743
}
×
744

745
RLM_API const char* realm_sync_session_get_file_path(const realm_sync_session_t* session) noexcept
746
{
×
747
    return (*session)->path().c_str();
×
748
}
×
749

750
RLM_API void realm_sync_session_pause(realm_sync_session_t* session) noexcept
751
{
×
752
    (*session)->pause();
×
753
}
×
754

755
RLM_API void realm_sync_session_resume(realm_sync_session_t* session) noexcept
756
{
×
757
    (*session)->resume();
×
758
}
×
759

760
RLM_API void realm_sync_session_get_file_ident(realm_sync_session_t* session, realm_salted_file_ident_t* out) noexcept
761
{
×
762
    auto file_ident = (*session)->get_file_ident();
×
763
    out->ident = file_ident.ident;
×
764
    out->salt = file_ident.salt;
×
765
}
×
766

767
RLM_API realm_sync_session_connection_state_notification_token_t*
768
realm_sync_session_register_connection_state_change_callback(realm_sync_session_t* session,
769
                                                             realm_sync_connection_state_changed_func_t callback,
770
                                                             realm_userdata_t userdata,
771
                                                             realm_free_userdata_func_t userdata_free) noexcept
772
{
×
773
    std::function<realm::SyncSession::ConnectionStateChangeCallback> cb =
×
774
        [callback, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](auto old_state, auto new_state) {
×
775
            callback(userdata.get(), realm_sync_connection_state_e(old_state),
×
776
                     realm_sync_connection_state_e(new_state));
×
777
        };
×
778
    auto token = (*session)->register_connection_change_callback(std::move(cb));
×
779
    return new realm_sync_session_connection_state_notification_token_t{(*session), token};
×
780
}
×
781

782
RLM_API realm_sync_session_connection_state_notification_token_t* realm_sync_session_register_progress_notifier(
783
    realm_sync_session_t* session, realm_sync_progress_func_t notifier, realm_sync_progress_direction_e direction,
784
    bool is_streaming, realm_userdata_t userdata, realm_free_userdata_func_t userdata_free) noexcept
785
{
×
786
    std::function<realm::SyncSession::ProgressNotifierCallback> cb =
×
787
        [notifier, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](
×
788
            uint64_t transferred, uint64_t transferrable, double progress_estimate) {
×
789
            notifier(userdata.get(), transferred, transferrable, progress_estimate);
×
790
        };
×
791
    auto token = (*session)->register_progress_notifier(std::move(cb), SyncSession::ProgressDirection(direction),
×
792
                                                        is_streaming);
×
793
    return new realm_sync_session_connection_state_notification_token_t{(*session), token};
×
794
}
×
795

796
RLM_API void realm_sync_session_wait_for_download_completion(realm_sync_session_t* session,
797
                                                             realm_sync_wait_for_completion_func_t done,
798
                                                             realm_userdata_t userdata,
799
                                                             realm_free_userdata_func_t userdata_free) noexcept
800
{
×
801
    util::UniqueFunction<void(Status)> cb =
×
802
        [done, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](Status s) {
×
803
            if (!s.is_ok()) {
×
804
                realm_error_t error = to_capi(s);
×
805
                done(userdata.get(), &error);
×
806
            }
×
807
            else {
×
808
                done(userdata.get(), nullptr);
×
809
            }
×
810
        };
×
811
    (*session)->wait_for_download_completion(std::move(cb));
×
812
}
×
813

814
RLM_API void realm_sync_session_wait_for_upload_completion(realm_sync_session_t* session,
815
                                                           realm_sync_wait_for_completion_func_t done,
816
                                                           realm_userdata_t userdata,
817
                                                           realm_free_userdata_func_t userdata_free) noexcept
818
{
×
819
    util::UniqueFunction<void(Status)> cb =
×
820
        [done, userdata = SharedUserdata(userdata, FreeUserdata(userdata_free))](Status s) {
×
821
            if (!s.is_ok()) {
×
822
                realm_error_t error = to_capi(s);
×
823
                done(userdata.get(), &error);
×
824
            }
×
825
            else {
×
826
                done(userdata.get(), nullptr);
×
827
            }
×
828
        };
×
829
    (*session)->wait_for_upload_completion(std::move(cb));
×
830
}
×
831

832
RLM_API void realm_sync_session_handle_error_for_testing(const realm_sync_session_t* session,
833
                                                         realm_errno_e error_code, const char* error_str,
834
                                                         bool is_fatal)
835
{
×
836
    REALM_ASSERT(session);
×
837
    SyncSession::OnlyForTesting::handle_error(
×
838
        *session->get(),
×
NEW
839
        sync::SessionErrorInfo{Status{static_cast<ErrorCodes::Error>(error_code), error_str}, is_fatal});
×
840
}
×
841

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