From cd6164ac4de7360c469df225102b5473841d8875 Mon Sep 17 00:00:00 2001 From: Dachary Carey Date: Mon, 8 Jan 2024 17:20:12 -0500 Subject: [PATCH 1/5] C++: Add new sync control methods --- examples/cpp/sync/CMakeLists.txt | 1 + examples/cpp/sync/quick-start.cpp | 20 +-- examples/cpp/sync/sync-session.cpp | 97 +++++++++++++++ .../quick-start.snippet.open-synced-realm.cpp | 2 - .../sync-session.snippet.connection-state.cpp | 1 + ...sion.snippet.observe-connection-change.cpp | 5 + .../cpp/sync-session.snippet.pause.cpp | 1 + .../cpp/sync-session.snippet.reconnect.cpp | 1 + .../cpp/sync-session.snippet.resume.cpp | 1 + ... => sync-session.snippet.sync-session.cpp} | 0 ...pp => sync-session.snippet.sync-state.cpp} | 0 ...n.snippet.unregister-observation-token.cpp | 1 + ...ync-session.snippet.wait-for-download.cpp} | 0 ... sync-session.snippet.wait-for-upload.cpp} | 0 source/sdk/cpp/sync/manage-sync-session.txt | 115 +++++++++++++++++- 15 files changed, 221 insertions(+), 24 deletions(-) create mode 100644 examples/cpp/sync/sync-session.cpp create mode 100644 source/examples/generated/cpp/sync-session.snippet.connection-state.cpp create mode 100644 source/examples/generated/cpp/sync-session.snippet.observe-connection-change.cpp create mode 100644 source/examples/generated/cpp/sync-session.snippet.pause.cpp create mode 100644 source/examples/generated/cpp/sync-session.snippet.reconnect.cpp create mode 100644 source/examples/generated/cpp/sync-session.snippet.resume.cpp rename source/examples/generated/cpp/{quick-start.snippet.sync-session.cpp => sync-session.snippet.sync-session.cpp} (100%) rename source/examples/generated/cpp/{quick-start.snippet.sync-state.cpp => sync-session.snippet.sync-state.cpp} (100%) create mode 100644 source/examples/generated/cpp/sync-session.snippet.unregister-observation-token.cpp rename source/examples/generated/cpp/{quick-start.snippet.wait-for-download.cpp => sync-session.snippet.wait-for-download.cpp} (100%) rename source/examples/generated/cpp/{quick-start.snippet.wait-for-upload.cpp => sync-session.snippet.wait-for-upload.cpp} (100%) diff --git a/examples/cpp/sync/CMakeLists.txt b/examples/cpp/sync/CMakeLists.txt index 6e06ee19dd..cebcb990b0 100644 --- a/examples/cpp/sync/CMakeLists.txt +++ b/examples/cpp/sync/CMakeLists.txt @@ -32,6 +32,7 @@ add_executable(examples-sync flexible-sync.cpp quick-start.cpp sync-errors.cpp + sync-session.cpp ) target_link_libraries(examples-sync PRIVATE Catch2::Catch2WithMain) diff --git a/examples/cpp/sync/quick-start.cpp b/examples/cpp/sync/quick-start.cpp index 50d5ce4788..8434258442 100644 --- a/examples/cpp/sync/quick-start.cpp +++ b/examples/cpp/sync/quick-start.cpp @@ -120,14 +120,8 @@ TEST_CASE("sync quick start", "[realm][write][sync][sync-logger]") { // :snippet-start: open-synced-realm auto syncConfig = user.flexible_sync_configuration(); auto realm = realm::db(syncConfig); - // :snippet-start: sync-session - auto syncSession = realm.get_sync_session(); - // :snippet-end: - // :snippet-start: sync-state - syncSession->state(); - // :snippet-end: // :remove-start: - syncSession->wait_for_download_completion().get(); + realm.get_sync_session()->wait_for_download_completion().get(); realm.refresh(); // Remove any existing subscriptions before adding the one for this example auto clearInitialSubscriptions = @@ -150,13 +144,6 @@ TEST_CASE("sync quick start", "[realm][write][sync][sync-logger]") { .get(); // :snippet-end: CHECK(updateSubscriptionSuccess == true); - // We don't actually need this here - we use it up above - // in the Bluehawk remove block, but adding it to show - // a relevant Bluehawked example in the docs - // :snippet-start: wait-for-download - syncSession->wait_for_download_completion().get(); - realm.refresh(); - // :snippet-end: // :snippet-start: write-to-synced-realm auto todo = realm::Sync_Todo{.name = "Create a Sync todo item", .status = "In Progress", @@ -169,10 +156,7 @@ TEST_CASE("sync quick start", "[realm][write][sync][sync-logger]") { CHECK(todos.size() == 1); auto specificTodo = todos[0]; realm.write([&] { realm.remove(specificTodo); }); - - // :snippet-start: wait-for-upload - syncSession->wait_for_upload_completion().get(); - // :snippet-end: + realm.get_sync_session()->wait_for_upload_completion().get(); } // :replace-end: diff --git a/examples/cpp/sync/sync-session.cpp b/examples/cpp/sync/sync-session.cpp new file mode 100644 index 0000000000..fc8e637ecd --- /dev/null +++ b/examples/cpp/sync/sync-session.cpp @@ -0,0 +1,97 @@ +#include +#include + +static const std::string APP_ID = "cpp-tester-uliix"; + +// :replace-start: { +// "terms": { +// "Local_": "", +// "Sync_": "" +// } +// } + +namespace realm { +struct Sync_Todo { + realm::primary_key _id{realm::object_id::generate()}; + std::string name; + std::string status; + std::string ownerId; +}; +REALM_SCHEMA(Sync_Todo, _id, name, status, ownerId); +} // namespace realm + +TEST_CASE("sync session", "[realm][write][sync]") { + auto appConfig = realm::App::configuration(); + appConfig.app_id = APP_ID; + auto app = realm::App(appConfig); + auto user = app.login(realm::App::credentials::anonymous()).get(); + auto syncConfig = user.flexible_sync_configuration(); + auto realm = realm::db(syncConfig); + // :snippet-start: sync-session + auto syncSession = realm.get_sync_session(); + // :snippet-end: + // :snippet-start: sync-state + syncSession->state(); + // :snippet-end: + // :snippet-start: wait-for-download + syncSession->wait_for_download_completion().get(); + realm.refresh(); + // :snippet-end: + // Remove any existing subscriptions before adding the one for this example + auto clearInitialSubscriptions = + realm.subscriptions().update([](auto& subs) { subs.clear(); }).get(); + CHECK(clearInitialSubscriptions == true); + CHECK(realm.subscriptions().size() == 0); + // For this example, get the userId for the Flexible Sync query + auto userId = user.identifier(); + auto subscriptions = realm.subscriptions(); + auto updateSubscriptionSuccess = + subscriptions + .update([&](realm::mutable_sync_subscription_set& subs) { + subs.add("todos", [&userId](auto& obj) { + // For this example, get only Sync_Todo items where the ownerId + // property value is equal to the userId of the logged-in user. + return obj.ownerId == userId; + }); + }) + .get(); + CHECK(updateSubscriptionSuccess == true); + auto todo = realm::Sync_Todo{.name = "Create a Sync todo item", + .status = "In Progress", + .ownerId = userId}; + + realm.write([&] { realm.add(std::move(todo)); }); + + // :snippet-start: pause + syncSession->pause(); + // :snippet-end: + // :snippet-start: connection-state + syncSession->connection_state(); + // :snippet-end: + CHECK(syncSession->connection_state() == + realm::internal::bridge::sync_session::connection_state::disconnected); + auto todos = realm.objects(); + CHECK(todos.size() == 1); + auto specificTodo = todos[0]; + realm.write([&] { realm.remove(specificTodo); }); + // :snippet-start: resume + syncSession->resume(); + // :snippet-end: + // :snippet-start: observe-connection-change + auto connectionToken = syncSession->observe_connection_change( + [&](enum realm::sync_session::connection_state, + enum realm::sync_session::connection_state new_state) { + // Register a block to execute when connection state changes. + }); + // :snippet-end: + // :snippet-start: reconnect + syncSession->reconnect(); + // :snippet-end: + // :snippet-start: unregister-observation-token + syncSession->unregister_connection_change_observer(connectionToken); + // :snippet-end: + // :snippet-start: wait-for-upload + syncSession->wait_for_upload_completion().get(); + // :snippet-end: +} +// :replace-end: diff --git a/source/examples/generated/cpp/quick-start.snippet.open-synced-realm.cpp b/source/examples/generated/cpp/quick-start.snippet.open-synced-realm.cpp index c2b0146bf8..1f09a12478 100644 --- a/source/examples/generated/cpp/quick-start.snippet.open-synced-realm.cpp +++ b/source/examples/generated/cpp/quick-start.snippet.open-synced-realm.cpp @@ -1,7 +1,5 @@ auto syncConfig = user.flexible_sync_configuration(); auto realm = realm::db(syncConfig); -auto syncSession = realm.get_sync_session(); -syncSession->state(); // For this example, get the userId for the Flexible Sync query auto userId = user.identifier(); auto subscriptions = realm.subscriptions(); diff --git a/source/examples/generated/cpp/sync-session.snippet.connection-state.cpp b/source/examples/generated/cpp/sync-session.snippet.connection-state.cpp new file mode 100644 index 0000000000..3a189b267c --- /dev/null +++ b/source/examples/generated/cpp/sync-session.snippet.connection-state.cpp @@ -0,0 +1 @@ +syncSession->connection_state(); diff --git a/source/examples/generated/cpp/sync-session.snippet.observe-connection-change.cpp b/source/examples/generated/cpp/sync-session.snippet.observe-connection-change.cpp new file mode 100644 index 0000000000..79579b9a0b --- /dev/null +++ b/source/examples/generated/cpp/sync-session.snippet.observe-connection-change.cpp @@ -0,0 +1,5 @@ +auto connectionToken = syncSession->observe_connection_change( + [&](enum realm::sync_session::connection_state, + enum realm::sync_session::connection_state new_state) { + // Register a block to execute when connection state changes. + }); diff --git a/source/examples/generated/cpp/sync-session.snippet.pause.cpp b/source/examples/generated/cpp/sync-session.snippet.pause.cpp new file mode 100644 index 0000000000..5da4adf8b8 --- /dev/null +++ b/source/examples/generated/cpp/sync-session.snippet.pause.cpp @@ -0,0 +1 @@ +syncSession->pause(); diff --git a/source/examples/generated/cpp/sync-session.snippet.reconnect.cpp b/source/examples/generated/cpp/sync-session.snippet.reconnect.cpp new file mode 100644 index 0000000000..1a156cd4ba --- /dev/null +++ b/source/examples/generated/cpp/sync-session.snippet.reconnect.cpp @@ -0,0 +1 @@ +syncSession->reconnect(); diff --git a/source/examples/generated/cpp/sync-session.snippet.resume.cpp b/source/examples/generated/cpp/sync-session.snippet.resume.cpp new file mode 100644 index 0000000000..3b48b7134b --- /dev/null +++ b/source/examples/generated/cpp/sync-session.snippet.resume.cpp @@ -0,0 +1 @@ +syncSession->resume(); diff --git a/source/examples/generated/cpp/quick-start.snippet.sync-session.cpp b/source/examples/generated/cpp/sync-session.snippet.sync-session.cpp similarity index 100% rename from source/examples/generated/cpp/quick-start.snippet.sync-session.cpp rename to source/examples/generated/cpp/sync-session.snippet.sync-session.cpp diff --git a/source/examples/generated/cpp/quick-start.snippet.sync-state.cpp b/source/examples/generated/cpp/sync-session.snippet.sync-state.cpp similarity index 100% rename from source/examples/generated/cpp/quick-start.snippet.sync-state.cpp rename to source/examples/generated/cpp/sync-session.snippet.sync-state.cpp diff --git a/source/examples/generated/cpp/sync-session.snippet.unregister-observation-token.cpp b/source/examples/generated/cpp/sync-session.snippet.unregister-observation-token.cpp new file mode 100644 index 0000000000..09bba2e0e9 --- /dev/null +++ b/source/examples/generated/cpp/sync-session.snippet.unregister-observation-token.cpp @@ -0,0 +1 @@ +syncSession->unregister_connection_change_observer(connectionToken); diff --git a/source/examples/generated/cpp/quick-start.snippet.wait-for-download.cpp b/source/examples/generated/cpp/sync-session.snippet.wait-for-download.cpp similarity index 100% rename from source/examples/generated/cpp/quick-start.snippet.wait-for-download.cpp rename to source/examples/generated/cpp/sync-session.snippet.wait-for-download.cpp diff --git a/source/examples/generated/cpp/quick-start.snippet.wait-for-upload.cpp b/source/examples/generated/cpp/sync-session.snippet.wait-for-upload.cpp similarity index 100% rename from source/examples/generated/cpp/quick-start.snippet.wait-for-upload.cpp rename to source/examples/generated/cpp/sync-session.snippet.wait-for-upload.cpp diff --git a/source/sdk/cpp/sync/manage-sync-session.txt b/source/sdk/cpp/sync/manage-sync-session.txt index 7d7b160426..93bf76beb3 100644 --- a/source/sdk/cpp/sync/manage-sync-session.txt +++ b/source/sdk/cpp/sync/manage-sync-session.txt @@ -39,9 +39,79 @@ You can use the member function :cpp-sdk:`get_sync_session() object for any synced realm. The SDK returns this object as an optional. It is a lightweight handle that you can pass around by value. -.. literalinclude:: /examples/generated/cpp/quick-start.snippet.sync-session.cpp +.. literalinclude:: /examples/generated/cpp/sync-session.snippet.sync-session.cpp :language: cpp +.. _cpp-check-network-connection: + +Check the Network Connection +---------------------------- + +.. tip:: + + The SDK's *offline-first* design means that you generally don't + need to check the current network connection state. That said, the + ``connection_state()`` property is available if your app calls for some + indication of connection state. + +To check the connection state, you can read the Sync session instance's +:cpp-sdk:`connection_state() +` +property directly. + +.. literalinclude:: /examples/generated/cpp/sync-session.snippet.connection-state.cpp + :language: cpp + +You can also observe the connection state with the +:cpp-sdk:`observe_connection_change() ` +function. This function registers a callback that the SDK invokes when the +underlying sync session changes its connection state. + +.. literalinclude:: /examples/generated/cpp/sync-session.snippet.observe-connection-change.cpp + :language: cpp + +If you register a connection change listener, you can unregister it when +you're done listening for changes. Call the sync session instance's +:cpp-sdk:`unregister_connection_change_observer() ` +method to unregister an observation token. + +.. literalinclude:: /examples/generated/cpp/sync-session.snippet.unregister-observation-token.cpp + :language: cpp + +The network connection state is distinct from the Device Sync connection state +that you can check with the ``state()`` method. For more information about +Sync connection state, refer to the Check the Sync State documentation on +this page. + +.. _cpp-pause-resume-sync-session: + +Pause or Resume a Sync Session +------------------------------ + +You can pause and resume the sync session on the realm. +Pausing a sync session only suspends that realm's sync session. If you have +more than one open realm, suspend does not affect the sync sessions for +other realms. + +To pause a sync session, call the Sync session's +:cpp-sdk:`pause() ` +method. + +.. literalinclude:: /examples/generated/cpp/sync-session.snippet.pause.cpp + :language: cpp + +To resume a sync session, call the sync session's +:cpp-sdk:`resume() structrealm_1_1internal_1_1bridge_1_1sync__session.html#a253ef9e08d9f4cf7c42edfd6b6f6df80>` +method. + +.. literalinclude:: /examples/generated/cpp/sync-session.snippet.resume.cpp + :language: cpp + +When to Pause a Sync Session +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. include:: /includes/when-to-pause-sync.rst + .. _cpp-sync-wait-for-changes: Wait for Changes to Upload and Download @@ -50,7 +120,7 @@ Wait for Changes to Upload and Download To wait for all changes to upload to Atlas from your synced realm, use the member function ``.wait_for_upload_completion()``. -.. literalinclude:: /examples/generated/cpp/quick-start.snippet.wait-for-upload.cpp +.. literalinclude:: /examples/generated/cpp/sync-session.snippet.wait-for-upload.cpp :language: cpp To wait for all changes from Atlas @@ -58,7 +128,7 @@ to download to your synced realm, use the member function ``wait_for_download_completion()``. Refresh the realm after downloading any changes to be sure it reflects the most recent data. -.. literalinclude:: /examples/generated/cpp/quick-start.snippet.wait-for-download.cpp +.. literalinclude:: /examples/generated/cpp/sync-session.snippet.wait-for-download.cpp :language: cpp .. _cpp-check-sync-state: @@ -71,5 +141,42 @@ You can use the :cpp-sdk:`sync_session member function ``state()`` to check whether the sync session is active. This returns an enum whose value reflects possible Device Sync states. -.. literalinclude:: /examples/generated/cpp/quick-start.snippet.sync-state.cpp +.. literalinclude:: /examples/generated/cpp/sync-session.snippet.sync-state.cpp :language: cpp + +The Sync connection state is distinct from the network connection state +that you can check with the ``connection_state()`` method. For more information +about network connection state, refer to the Check the Network Connection +documentation on this page. + +.. _cpp-reconnect-sync-sessions: + +Manually Reconnect All Sync Sessions +------------------------------------ + +Realm automatically detects when a device regains connectivity after being +offline and attempts to reconnect using an incremental backoff strategy. + +You can choose to manually trigger a reconnect attempt with a sync session's +:cpp-sdk:`reconnect() ` +method instead of waiting for the duration of the incremental backoff. This is +useful if you have a more accurate understanding of the network conditions +and don't want to rely on Realm's automatic reconnect detection. + +.. literalinclude:: /examples/generated/cpp/sync-session.snippet.reconnect.cpp + :language: cpp + +When you call this method, the SDK forces all sync sessions to *attempt* to +reconnect immediately. This resets any timers used for incremental +backoff. + +Calling this method does not guarantee the device can reconnect. If the SDK +gets a fatal error, or if the device is already connected or is trying to +connect, calling this method has no effect. + +.. important:: Cannot Reconnect Within Socket Read Timeout Duration + + Realm has an internal default socket read timeout of 2 minutes, where + Realm will time out if a read operation does not receive any data + within a 2-minute window. If you call ``reconnect()`` within that window, + the SDK does *not* attempt to reconnect. From c3487d0549ffe49d67d8fd322150e6423c35a987 Mon Sep 17 00:00:00 2001 From: Dachary Carey Date: Mon, 8 Jan 2024 17:29:28 -0500 Subject: [PATCH 2/5] Fix API reference links --- source/sdk/cpp/sync/manage-sync-session.txt | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/source/sdk/cpp/sync/manage-sync-session.txt b/source/sdk/cpp/sync/manage-sync-session.txt index 93bf76beb3..2f334f9965 100644 --- a/source/sdk/cpp/sync/manage-sync-session.txt +++ b/source/sdk/cpp/sync/manage-sync-session.txt @@ -54,10 +54,9 @@ Check the Network Connection ``connection_state()`` property is available if your app calls for some indication of connection state. -To check the connection state, you can read the Sync session instance's -:cpp-sdk:`connection_state() -` -property directly. +To check the connection state, you can read the +:cpp-sdk:`Sync session instance's ` +``connection_state()`` property directly. .. literalinclude:: /examples/generated/cpp/sync-session.snippet.connection-state.cpp :language: cpp @@ -101,7 +100,7 @@ method. :language: cpp To resume a sync session, call the sync session's -:cpp-sdk:`resume() structrealm_1_1internal_1_1bridge_1_1sync__session.html#a253ef9e08d9f4cf7c42edfd6b6f6df80>` +:cpp-sdk:`resume() ` method. .. literalinclude:: /examples/generated/cpp/sync-session.snippet.resume.cpp @@ -118,7 +117,7 @@ Wait for Changes to Upload and Download --------------------------------------- To wait for all changes to upload to Atlas from your synced realm, -use the member function ``.wait_for_upload_completion()``. +use the member function ``wait_for_upload_completion()``. .. literalinclude:: /examples/generated/cpp/sync-session.snippet.wait-for-upload.cpp :language: cpp From 597912ed56899e79c3dc2dcc6b1caf5c5140c232 Mon Sep 17 00:00:00 2001 From: Dachary Carey Date: Mon, 8 Jan 2024 17:32:46 -0500 Subject: [PATCH 3/5] Add meta keywords, description, and facet values --- source/sdk/cpp/quick-start.txt | 8 ++++++++ source/sdk/cpp/sync/manage-sync-session.txt | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/source/sdk/cpp/quick-start.txt b/source/sdk/cpp/quick-start.txt index 6fd6ff1099..89e283aea3 100644 --- a/source/sdk/cpp/quick-start.txt +++ b/source/sdk/cpp/quick-start.txt @@ -5,6 +5,14 @@ Quick Start - C++ SDK ===================== +.. meta:: + :keywords: code example + :description: Learn how to quickly get started with Atlas Device SDK for C++. + +.. facet:: + :name: genre + :values: tutorial + .. contents:: On this page :local: :backlinks: none diff --git a/source/sdk/cpp/sync/manage-sync-session.txt b/source/sdk/cpp/sync/manage-sync-session.txt index 2f334f9965..19c1f850d8 100644 --- a/source/sdk/cpp/sync/manage-sync-session.txt +++ b/source/sdk/cpp/sync/manage-sync-session.txt @@ -4,6 +4,14 @@ Manage a Sync Session - C++ SDK =============================== +.. meta:: + :keywords: code example + :description: Check and manage network and Device Sync connection state through the sync session. + +.. facet:: + :name: genre + :values: reference + .. contents:: On this page :local: :backlinks: none From c4e8a6207bbcd3ca7def286def250cc18e5408b4 Mon Sep 17 00:00:00 2001 From: Dachary Date: Tue, 9 Jan 2024 09:03:57 -0500 Subject: [PATCH 4/5] Apply review feedback Co-authored-by: cbullinger <115956901+cbullinger@users.noreply.github.com> --- source/sdk/cpp/sync/manage-sync-session.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/sdk/cpp/sync/manage-sync-session.txt b/source/sdk/cpp/sync/manage-sync-session.txt index 19c1f850d8..f96de0c695 100644 --- a/source/sdk/cpp/sync/manage-sync-session.txt +++ b/source/sdk/cpp/sync/manage-sync-session.txt @@ -63,7 +63,7 @@ Check the Network Connection indication of connection state. To check the connection state, you can read the -:cpp-sdk:`Sync session instance's ` +:cpp-sdk:`sync session instance's ` ``connection_state()`` property directly. .. literalinclude:: /examples/generated/cpp/sync-session.snippet.connection-state.cpp @@ -87,7 +87,7 @@ method to unregister an observation token. The network connection state is distinct from the Device Sync connection state that you can check with the ``state()`` method. For more information about -Sync connection state, refer to the Check the Sync State documentation on +sync connection state, refer to the Check the Sync State documentation on this page. .. _cpp-pause-resume-sync-session: @@ -100,7 +100,7 @@ Pausing a sync session only suspends that realm's sync session. If you have more than one open realm, suspend does not affect the sync sessions for other realms. -To pause a sync session, call the Sync session's +To pause a sync session, call the sync session's :cpp-sdk:`pause() ` method. @@ -151,7 +151,7 @@ This returns an enum whose value reflects possible Device Sync states. .. literalinclude:: /examples/generated/cpp/sync-session.snippet.sync-state.cpp :language: cpp -The Sync connection state is distinct from the network connection state +The sync connection state is distinct from the network connection state that you can check with the ``connection_state()`` method. For more information about network connection state, refer to the Check the Network Connection documentation on this page. From a51b724da5c32b5fbe1c513c0aafe24a5885f80d Mon Sep 17 00:00:00 2001 From: Dachary Carey Date: Tue, 9 Jan 2024 09:09:31 -0500 Subject: [PATCH 5/5] Add a link to the API reference --- source/sdk/cpp/sync/manage-sync-session.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/source/sdk/cpp/sync/manage-sync-session.txt b/source/sdk/cpp/sync/manage-sync-session.txt index f96de0c695..a4dd5444f6 100644 --- a/source/sdk/cpp/sync/manage-sync-session.txt +++ b/source/sdk/cpp/sync/manage-sync-session.txt @@ -124,6 +124,13 @@ When to Pause a Sync Session Wait for Changes to Upload and Download --------------------------------------- +You can use the +:cpp-sdk:`sync_session `'s +``wait_for_upload_completion()`` and ``wait_for_download_completion()`` +methods to wait for changes to upload to or download from Atlas. Both of these +methods can optionally take a callback to execute when upload or download +is complete. + To wait for all changes to upload to Atlas from your synced realm, use the member function ``wait_for_upload_completion()``.