Skip to content

Commit

Permalink
RCORE-2201 Add an implementation for the realm_app_config_get_sync_cl…
Browse files Browse the repository at this point in the history
…ient_config() function in the Core CAPI (#7891)

* Added back realm_app_config_set_sync_client_config() CAPI function
* Updated changelog and fixed compilation error
* Added setter functions for the sync_client_config in app_config
* Use different realm_sync_client_config_t based on REALM_APP_SERVICES setting
* Added comments around use of realm_sync_client_config_t when using REALM_APP_SERVICES
* Use static_cast<> instead of reinterpret_cast<>
  • Loading branch information
Michael Wilkerson-Barker authored Jul 17, 2024
1 parent e019c79 commit 1f0378a
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 35 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* On Windows devices Device Sync will additionally look up SSL certificates in the Windows Trusted Root Certification Authorities certificate store when establishing a connection. (PR [#7882](https://github.com/realm/realm-core/pull/7882))
* Updated the return type of `LogCategory::get_category_names()` from `std::vector<const char*>` to `std::vector<std::string_view>`. ([PR #7879](https://github.com/realm/realm-core/pull/7879))
* Added `realm_get_persisted_schema_version` for reading the version of the schema currently stored locally. (PR [#7873](https://github.com/realm/realm-core/pull/7873))
* Added `realm_app_config_get_sync_client_config()` function to the C_API to get the sync_client_config value in `realm_app_config_t` if REALM_APP_SERVICES is enabled. If REALM_APP_SERVICES is not available, `realm_sync_client_config_new()` is available to create a new `sync_client_config_t` to use when initializing the sync manager. ([PR #7891](https://github.com/realm/realm-core/pull/7891))

### Fixed
* <How do the end-user experience this issue? what was the impact?> ([#????](https://github.com/realm/realm-core/issues/????), since v?.?.?)
Expand Down
17 changes: 14 additions & 3 deletions src/realm.h
Original file line number Diff line number Diff line change
Expand Up @@ -3023,8 +3023,6 @@ RLM_API void realm_app_config_set_metadata_mode(realm_app_config_t*,
RLM_API void realm_app_config_set_metadata_encryption_key(realm_app_config_t*, const uint8_t[64]) RLM_API_NOEXCEPT;
RLM_API void realm_app_config_set_security_access_group(realm_app_config_t*, const char*) RLM_API_NOEXCEPT;

RLM_API realm_sync_client_config_t* realm_app_config_get_sync_client_config(realm_app_config_t*) RLM_API_NOEXCEPT;

/**
* Get an existing @a realm_app_credentials_t and return it's json representation
* Note: the caller must delete the pointer to the string via realm_release
Expand Down Expand Up @@ -3746,8 +3744,21 @@ typedef void (*realm_async_open_task_completion_func_t)(realm_userdata_t userdat
// callback runs.
typedef void (*realm_async_open_task_init_subscription_func_t)(realm_thread_safe_reference_t* realm,
realm_userdata_t userdata);

#if REALM_APP_SERVICES
// If using App Services, the realm_sync_client_config_t instance is part of the
// realm_app_config_t structure and this function returns a pointer to that
// member property. The realm_sync_client_config_t reference returned by this
// function should not be freed using realm_release.
RLM_API realm_sync_client_config_t* realm_app_config_get_sync_client_config(realm_app_config_t*) RLM_API_NOEXCEPT;
#else
// If not using App Services, the realm_app_config_t structure is not defined, and
// the real_sync_client_config_t structure returned by this function is meant to be
// used with realm_sync_manager_create() to create a separate Sync Manager instance.
// The realm_sync_client_config_t instance returned by this function will need to be
// manually freed using realm_release.
RLM_API realm_sync_client_config_t* realm_sync_client_config_new(void) RLM_API_NOEXCEPT;
#endif // REALM_APP_SERVICES

RLM_API void realm_sync_client_config_set_reconnect_mode(realm_sync_client_config_t*,
realm_sync_client_reconnect_mode_e) RLM_API_NOEXCEPT;
RLM_API void realm_sync_client_config_set_multiplex_sessions(realm_sync_client_config_t*, bool) RLM_API_NOEXCEPT;
Expand Down
5 changes: 5 additions & 0 deletions src/realm/object-store/c_api/app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,11 @@ RLM_API const char* realm_app_credentials_serialize_as_json(realm_app_credential
});
}

RLM_API realm_sync_client_config_t* realm_app_config_get_sync_client_config(realm_app_config_t* app_config) noexcept
{
return static_cast<realm_sync_client_config_t*>(&app_config->sync_client_config);
}

RLM_API realm_app_t* realm_app_create(const realm_app_config_t* app_config)
{
return wrap_err([&] {
Expand Down
2 changes: 2 additions & 0 deletions src/realm/object-store/c_api/sync.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,12 @@ static Query add_ordering_to_realm_query(Query realm_query, const DescriptorOrde
return realm_query;
}

#if !REALM_APP_SERVICES
RLM_API realm_sync_client_config_t* realm_sync_client_config_new(void) noexcept
{
return new realm_sync_client_config_t;
}
#endif // !REALM_APP_SERVICES

RLM_API void realm_sync_client_config_set_reconnect_mode(realm_sync_client_config_t* config,
realm_sync_client_reconnect_mode_e mode) noexcept
Expand Down
12 changes: 12 additions & 0 deletions src/realm/object-store/c_api/types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -617,9 +617,21 @@ struct realm_http_transport : realm::c_api::WrapC, std::shared_ptr<realm::app::G
}
};

#if REALM_APP_SERVICES
// This class doesn't support realm_release() since it is only meant to be used
// as a CAPI-compatible reference to the SyncClientConfig member variable that
// is part of AppConfig.
// To avoid data misalignment or other conflicts with the original SyncClientConfig,
// do not add any additional functions or member variables to this class.
struct realm_sync_client_config final : realm::SyncClientConfig {
using SyncClientConfig::SyncClientConfig;
};
#else
// This class must be freed using realm_release()
struct realm_sync_client_config : realm::c_api::WrapC, realm::SyncClientConfig {
using SyncClientConfig::SyncClientConfig;
};
#endif // REALM_APP_SERVICES

struct realm_sync_config : realm::c_api::WrapC, realm::SyncConfig {
using SyncConfig::SyncConfig;
Expand Down
97 changes: 65 additions & 32 deletions test/object-store/c_api/c_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include "../util/test_path.hpp"
#include "../util/unit_test_transport.hpp"

#include <realm/object-store/c_api/types.hpp>
#include <realm/object-store/sync/app_utils.hpp>
#include <realm/object-store/sync/sync_user.hpp>
#include <realm/sync/client_base.hpp>
Expand Down Expand Up @@ -537,36 +538,51 @@ TEST_CASE("C API (non-database)", "[c_api]") {

#if REALM_ENABLE_SYNC
SECTION("sync_client_config_t") {
#if REALM_APP_SERVICES
// Make a dummy app config and make sure the sync_client_config is updated
const uint64_t request_timeout = 2500;
auto transport = std::make_shared<UnitTestTransport>(request_timeout);
auto http_transport = realm_http_transport(transport);
auto app_config = cptr(realm_app_config_new("app_id_123", &http_transport));
auto sync_client_config = realm_app_config_get_sync_client_config(app_config.get());
#else
auto test_sync_client_config = cptr(realm_sync_client_config_new());
realm_sync_client_config_set_reconnect_mode(test_sync_client_config.get(),
RLM_SYNC_CLIENT_RECONNECT_MODE_TESTING);
CHECK(test_sync_client_config->reconnect_mode ==
auto sync_client_config = test_sync_client_config.get();
#endif // REALM_APP_SERVICES

realm_sync_client_config_set_reconnect_mode(sync_client_config, RLM_SYNC_CLIENT_RECONNECT_MODE_TESTING);
CHECK(sync_client_config->reconnect_mode ==
static_cast<ReconnectMode>(RLM_SYNC_CLIENT_RECONNECT_MODE_TESTING));
realm_sync_client_config_set_multiplex_sessions(test_sync_client_config.get(), true);
CHECK(test_sync_client_config->multiplex_sessions);
realm_sync_client_config_set_multiplex_sessions(test_sync_client_config.get(), false);
CHECK_FALSE(test_sync_client_config->multiplex_sessions);
realm_sync_client_config_set_user_agent_binding_info(test_sync_client_config.get(), "some user agent stg");
CHECK(test_sync_client_config->user_agent_binding_info == "some user agent stg");
realm_sync_client_config_set_user_agent_application_info(test_sync_client_config.get(), "some application");
CHECK(test_sync_client_config->user_agent_application_info == "some application");
realm_sync_client_config_set_connect_timeout(test_sync_client_config.get(), 666);
CHECK(test_sync_client_config->timeouts.connect_timeout == 666);
realm_sync_client_config_set_connection_linger_time(test_sync_client_config.get(), 999);
CHECK(test_sync_client_config->timeouts.connection_linger_time == 999);
realm_sync_client_config_set_ping_keepalive_period(test_sync_client_config.get(), 555);
CHECK(test_sync_client_config->timeouts.ping_keepalive_period == 555);
realm_sync_client_config_set_pong_keepalive_timeout(test_sync_client_config.get(), 100000);
CHECK(test_sync_client_config->timeouts.pong_keepalive_timeout == 100000);
realm_sync_client_config_set_fast_reconnect_limit(test_sync_client_config.get(), 1099);
CHECK(test_sync_client_config->timeouts.fast_reconnect_limit == 1099);
realm_sync_client_config_set_resumption_delay_interval(test_sync_client_config.get(), 1024);
CHECK(test_sync_client_config->timeouts.reconnect_backoff_info.resumption_delay_interval.count() == 1024);
realm_sync_client_config_set_max_resumption_delay_interval(test_sync_client_config.get(), 600024);
CHECK(test_sync_client_config->timeouts.reconnect_backoff_info.max_resumption_delay_interval.count() ==
600024);
realm_sync_client_config_set_resumption_delay_backoff_multiplier(test_sync_client_config.get(), 1010);
CHECK(test_sync_client_config->timeouts.reconnect_backoff_info.resumption_delay_backoff_multiplier == 1010);
realm_sync_client_config_set_multiplex_sessions(sync_client_config, true);
CHECK(sync_client_config->multiplex_sessions);
realm_sync_client_config_set_multiplex_sessions(sync_client_config, false);
realm_sync_client_config_set_user_agent_binding_info(sync_client_config, "some user agent stg");
realm_sync_client_config_set_user_agent_application_info(sync_client_config, "some application");
realm_sync_client_config_set_connect_timeout(sync_client_config, 666);
realm_sync_client_config_set_connection_linger_time(sync_client_config, 999);
realm_sync_client_config_set_ping_keepalive_period(sync_client_config, 555);
realm_sync_client_config_set_pong_keepalive_timeout(sync_client_config, 100000);
realm_sync_client_config_set_fast_reconnect_limit(sync_client_config, 1099);
realm_sync_client_config_set_resumption_delay_interval(sync_client_config, 1024);
realm_sync_client_config_set_max_resumption_delay_interval(sync_client_config, 600024);
realm_sync_client_config_set_resumption_delay_backoff_multiplier(sync_client_config, 1010);
auto verify_sync_client_config = [](SyncClientConfig* config) {
CHECK_FALSE(config->multiplex_sessions);
CHECK(config->user_agent_binding_info == "some user agent stg");
CHECK(config->user_agent_application_info == "some application");
CHECK(config->timeouts.connect_timeout == 666);
CHECK(config->timeouts.connection_linger_time == 999);
CHECK(config->timeouts.ping_keepalive_period == 555);
CHECK(config->timeouts.pong_keepalive_timeout == 100000);
CHECK(config->timeouts.fast_reconnect_limit == 1099);
CHECK(config->timeouts.reconnect_backoff_info.resumption_delay_interval.count() == 1024);
CHECK(config->timeouts.reconnect_backoff_info.max_resumption_delay_interval.count() == 600024);
CHECK(config->timeouts.reconnect_backoff_info.resumption_delay_backoff_multiplier == 1010);
};
verify_sync_client_config(sync_client_config);
#if REALM_APP_SERVICES
verify_sync_client_config(&app_config->sync_client_config);
#endif // REALM_APP_SERVICES
}

#if !REALM_APP_SERVICES
Expand Down Expand Up @@ -824,6 +840,11 @@ TEST_CASE("C API (non-database)", "[c_api]") {
realm_app_config_set_metadata_mode(app_config.get(), RLM_SYNC_CLIENT_METADATA_MODE_DISABLED);
realm_app_config_set_security_access_group(app_config.get(), "");

auto sync_client_config = realm_app_config_get_sync_client_config(app_config.get());
realm_sync_client_config_set_connect_timeout(sync_client_config, 9876543); // some bogus value
// Make sure app_config's sync_client_config has the value we set
CHECK(app_config->sync_client_config.timeouts.connect_timeout == 9876543);

auto test_app = cptr(realm_app_create(app_config.get()));
realm_user_t* sync_user;
auto user_data_free = [](realm_userdata_t) {};
Expand Down Expand Up @@ -5996,9 +6017,15 @@ TEST_CASE("C API - binding callback thread observer", "[sync][c_api]") {
};

{
auto config = cptr(realm_sync_client_config_new());
#if REALM_APP_SERVICES
struct realm_sync_client_config config_struct {};
auto config = &config_struct;
#else
auto config_ptr = cptr(realm_sync_client_config_new());
auto config = config_ptr.get();
#endif // REALM_APP_SERVICES
realm_sync_client_config_set_default_binding_thread_observer(
config.get(), bcto_on_thread_create, bcto_on_thread_destroy, bcto_on_thread_error,
config, bcto_on_thread_create, bcto_on_thread_destroy, bcto_on_thread_error,
static_cast<realm_userdata_t>(&bcto_user_data), bcto_free_userdata);
REQUIRE(config->default_socket_provider_thread_observer);
auto observer_ptr =
Expand Down Expand Up @@ -6029,8 +6056,14 @@ TEST_CASE("C API - binding callback thread observer", "[sync][c_api]") {
REQUIRE(bcto_user_data.bcto_deleted == true);

{
auto config = cptr(realm_sync_client_config_new());
realm_sync_client_config_set_default_binding_thread_observer(config.get(), nullptr, nullptr, nullptr, nullptr,
#if REALM_APP_SERVICES
struct realm_sync_client_config config_struct {};
auto config = &config_struct;
#else
auto config_ptr = cptr(realm_sync_client_config_new());
auto config = config_ptr.get();
#endif // REALM_APP_SERVICES
realm_sync_client_config_set_default_binding_thread_observer(config, nullptr, nullptr, nullptr, nullptr,
nullptr);
auto no_handle_error_ptr =
static_cast<CBindingThreadObserver*>(config->default_socket_provider_thread_observer.get());
Expand Down

0 comments on commit 1f0378a

Please sign in to comment.