Docs Menu
Docs Home
/ /
Servicios de aplicaciones Atlas

Tutorial: Atlas Device Sync para C++ con FTXUI

Tiempo estimado para completar: 30 minutos, dependiendo de su experiencia con C++

El SDK de dispositivos Atlas para C++ permite almacenar y sincronizar datos entre teléfonos, tabletas, wearables o dispositivos IoT. Este tutorial se basa en la aplicación de plantilla de C++. cpp.todo.flex, que ilustra la creación de una aplicación GUI de terminal de lista de tareas pendientes creada con FTXUIEsta aplicación permite a los usuarios:

  • Registrar su correo electrónico como una nueva cuenta de usuario.

  • Inicie sesión en su cuenta con su correo electrónico y contraseña (y cierre sesión más tarde).

  • Ver, crear, modificar y eliminar sus propias tareas.

  • Ver todas las tareas, incluso aquellas en las que el usuario no es el propietario.

La aplicación de plantilla también proporciona un interruptor que simula el dispositivo en modo sin conexión. Este interruptor permite probar rápidamente la sincronización del dispositivo en el simulador, simulando que el usuario no tiene conexión a internet. Sin embargo, es probable que este interruptor se elimine en una aplicación de producción.

Este tutorial se basa en la aplicación de plantillas. Agregará un nuevo priority campo al Item modelo existente y actualizará la suscripción de Sincronización flexible para mostrar solo elementos dentro de un rango de prioridades.

Este tutorial ilustra cómo adaptar la aplicación de plantilla a sus necesidades. Dada la estructura actual de la aplicación, no es necesario realizar este cambio.

En este tutorial aprenderás a:

  • Actualice un modelo de objetos de C++ con un cambio ininterrumpido.

  • Actualizar una suscripción de sincronización de dispositivos.

  • Agregue un campo consultable a la configuración de sincronización del dispositivo en el servidor para cambiar qué datos se sincronizan.

Tip

Si prefieres comenzar con tu propia aplicación en lugar de seguir un tutorial guiado, consulta la Guía rápida de C++. Incluye ejemplos de código que se pueden copiar y la información esencial que necesitas para configurar un backend de Atlas App Services.

  • Asegúrate de tener instalado el software necesario. La aplicación de plantilla de C++ presupone que tienes:

    • Versión deCMake. 3o más reciente.25

    • C++ 17 o más reciente.

Este tutorial se basa en la aplicación de plantilla de sincronización de C++ llamada cpp.todo.flex. Comenzamos con la aplicación predeterminada y creamos nuevas funciones a partir de ella.

Para obtener más información sobre las aplicaciones de plantilla, consulte Aplicaciones de plantilla.

Si aún no tiene una cuenta Atlas, regístrese para implementar una aplicación de plantilla.

Siga el procedimiento descrito en la guía Crear una aplicación de servicios de aplicaciones y seleccione Create App from TemplateSeleccione la plantilla Real-time Sync. Esto crea una aplicación de Servicios de Aplicaciones preconfigurada para usarla con uno de los clientes de la plantilla de Sincronización de Dispositivos.

Después de crear una aplicación de plantilla, la interfaz de usuario muestra un modal con la etiqueta Get the Front-end Code for your Template. Este modal proporciona instrucciones para descargar el código del cliente de la aplicación de plantilla como un archivo .zip o usar la CLI de App Services para obtener el cliente.

La aplicación de plantilla de C++ aún no está disponible para descargar en la interfaz de App Services. Usa la CLI o clona el repositorio desde GitHub para obtener el código del cliente.

El comando de creación de aplicaciones appservices configura el backend y crea una aplicación de plantilla C++ para que la uses como base para este tutorial.

Ejecute el siguiente comando en una ventana de terminal para crear una aplicación llamada "MyTutorialApp" que se implementa en la región US-VA con su entorno configurado en "desarrollo" (en lugar de producción o control de calidad).

appservices app create \
--name MyTutorialApp \
--template cpp.todo.flex \
--deployment-model global \
--environment development

El comando crea un nuevo directorio en su ruta actual con el mismo nombre que el valor del indicador --name.

Puedes bifurcar y clonar un repositorio de GitHub que contenga el código del cliente de Device Sync. El código del cliente en C++ está disponible en https://github.com/mongodb/template-app-cpp-todo.

Si usa este proceso para obtener el código del cliente, debe crear una aplicación de plantilla para usarla con el cliente. Siga las instrucciones de "Crear una aplicación de plantilla" para usar la interfaz de usuario de Atlas App Services, la CLI de App Services o la API de administración para crear una aplicación de plantilla de Device Sync.

1

Abra el código del cliente frontend en su IDE preferido.

Si clonaste el cliente desde un repositorio de GitHub, debes insertar manualmente el ID de la aplicación de App Services en el lugar correspondiente de tu cliente. Sigue las instrucciones Configuration del cliente README.md para saber dónde insertar el ID de la aplicación.

2
  1. Cree un directorio para compilar la aplicación. Para mayor comodidad, el .gitignore empaquetado con la aplicación de plantilla ignora el directorio build dentro del directorio del cliente. Navegue al directorio de compilación.

    mkdir build && cd build
  2. Use CMake para crear el Makefile. Suponiendo que compila desde un directorio build dentro del directorio del cliente:

    cmake ../
  3. Use CMake para compilar el ejecutable de la aplicación. Este proceso tarda unos instantes, ya que instala las dependencias y compila el ejecutable.

    cmake --build .
3

Tómese unos minutos para explorar cómo se organiza el proyecto mientras CMake construye el ejecutable.

No trabajará directamente con estos archivos durante este tutorial, pero contienen código que demuestra el uso del SDK de C++:

Archivo
Propósito

controllers/app_controller.cpp

Usa la biblioteca nlohmann::json para leer valores de atlasConfig.json. Luego, usa estos valores para inicializar realm::App y guardarlo en el estado de la aplicación. App es la forma en que tu aplicación se comunica con el backend de App Services. Esto proporciona acceso a la autenticación y al objeto realm::user del usuario que inició sesión.

Para obtener más información sobre cómo puede personalizar la configuración de su aplicación, consulte: Conectarse a un backend de Atlas App Services.

Este código también configura AuthManager y ErrorManager. Contiene el flujo de navegación para enviar a los usuarios a LoginController o HomeController, dependiendo de si hay un usuario conectado.

managers/auth_manager.cpp

Lógica para registrar un usuario de correo electrónico/contraseña, iniciar o cerrar sesión y mostrar un mensaje de error cuando ocurren errores de autenticación.

En este tutorial, trabajarás con los siguientes archivos:

Archivo
Propósito

state/item.hpp

Definimos el objeto Item que almacenamos en la base de datos.

state/home_controller_state.hpp

Administrar el estado de la aplicación para la vista de Inicio.

controllers/home_controller.hpp

Contiene definiciones importantes para el controlador de vista de inicio.

controllers/home_controller.cpp

Implementa la vista de inicio. Esta es la vista donde un usuario conectado puede trabajar con la aplicación.

managers/database_manager.hpp

Contiene definiciones importantes para la sincronización de dispositivos y operaciones de base de datos.

managers/database_manager.cpp

Implementa algunas operaciones de sincronización de dispositivos y bases de datos, como crear elementos, cambiar suscripciones de consultas de sincronización de dispositivos y manejar errores de sincronización.

4

Sin modificar el código, debería poder ejecutar la aplicación en la terminal. Pase la ruta a atlasConfig.json como argumento al ejecutar la aplicación:

./sync_todo /path-to-file/atlasConfig.json

Ejecute la aplicación, registre una nueva cuenta de usuario y luego agregue un nuevo elemento a su lista de tareas pendientes.

Tip

Expande la ventana del terminal, si es necesario.

La parte superior de la pantalla de inicio contiene una fila de botones y un interruptor para ocultar las tareas completadas. Si la ventana de la terminal es demasiado pequeña, las etiquetas de texto de los botones no se mostrarán. Para ver las etiquetas, amplíe la ventana de la terminal y FTXUI renderizará el contenido para que se ajuste a la ventana más grande.

5

Inicie sesión en Atlas App Services. En la pestaña, haga Data Services clic Browse Collections en. En la lista de bases de datos, busque y expanda la todo base de datos y, a continuación, la Item colección. Debería ver el documento que creó en esta colección.

1

Ahora que ha confirmado que todo funciona correctamente, puede añadir cambios. En este tutorial, añadirá una propiedad priority a cada Item para poder filtrar los elementos por prioridad.

En una aplicación de producción, podrías añadir una enumeración PriorityLevel para restringir los valores posibles. En este tutorial, usaremos una propiedad numérica para agilizar el trabajo con el framework de la interfaz de usuario.

Para ello siga estos pasos:

  1. Abra el código del cliente en su IDE preferido.

  2. En el directorio state/, abra el archivo item.hpp.

  3. Agregue la siguiente propiedad a la estructura Item:

    int64_t priority;
  4. Agregue la nueva propiedad priority a REALM_SCHEMA():

    REALM_SCHEMA(Item, _id, isComplete, summary, owner_id, priority)

    El modelo Item ahora debería parecerse a:

    namespace realm {
    struct Item {
    realm::primary_key<realm::object_id> _id{realm::object_id::generate()};
    bool isComplete;
    std::string summary;
    std::string owner_id;
    int64_t priority;
    };
    REALM_SCHEMA(Item, _id, isComplete, summary, owner_id, priority)
    } // namespace realm
2
  1. En el directorio state, vaya a home_controller_state.hpp. Añada una nueva propiedad int bajo la propiedad newTaskIsComplete existente. Luego, añada un static const int para almacenar el valor int predeterminado de esta propiedad.

    La estructura HomeControllerState ahora podría parecerse a:

    struct HomeControllerState {
    static const int DEFAULT_TASK_PRIORITY = 3;
    // Used for creating a new task.
    std::string newTaskSummary;
    bool newTaskIsComplete{false};
    int newTaskPriority{DEFAULT_TASK_PRIORITY};
    ...more code here...
    };
  2. En el directorio controllers, vaya a home_controller.hpp. Este controlador representa la vista principal de la aplicación.

    Importar las bibliotecas de cadenas y vectores:

    #include <string>
    #include <vector>

    Cree una matriz de etiquetas de cadena para el nuevo elemento de interfaz de usuario prioritario:

    std::vector<std::string> priorityLevelLabels = {
    "Severe", "High", "Medium", "Low"
    };
  3. Aún en el directorio controllers, ve a home_controller.cpp. Aquí añadimos un elemento de la interfaz de usuario para que el usuario pueda establecer la prioridad del elemento. FTXUI ofrece dos elementos de la interfaz de usuario que puedes usar para esta función: Radiobox o Dropdown. En este tutorial, usaremos Dropdown, pero quizás prefieras Radiobox si no te gusta cómo se redistribuye la interfaz de usuario para mostrar el menú desplegable.

    Agregue esta nueva entrada de elemento de UI después de la línea auto newTaskCompletionStatus:

    auto newTaskPriorityDropdown = ftxui::Dropdown(
    &priorityLevelLabels,
    &_homeControllerState.newTaskPriority
    );

    En el cierre de la función auto saveButton, pase la selección de prioridad de la tarea a la llamada de la función _dbManager.addNew():

    _dbManager.addNew(
    _homeControllerState.newTaskIsComplete,
    _homeControllerState.newTaskSummary,
    _homeControllerState.newTaskPriority);

    Y luego agregue una línea para restablecer la selección de prioridad al valor predeterminado:

    _homeControllerState.newTaskPriority = HomeControllerState::DEFAULT_TASK_PRIORITY;

    Agregue el selector desplegable a auto newTaskLayout que establece el diseño de los elementos interactivos en el contenedor de filas de elementos:

    auto newTaskLayout = ftxui::Container::Horizontal(
    {inputNewTaskSummary, newTaskCompletionStatus, newTaskPriorityDropdown, saveButton});

    Esta sección de su código deberá ahora parecerse a:

    auto newTaskCompletionStatus = ftxui::Checkbox("Complete", &_homeControllerState.newTaskIsComplete);
    auto newTaskPriorityDropdown = ftxui::Dropdown(
    &priorityLevelLabels,
    &_homeControllerState.newTaskPriority);
    auto saveButton = ftxui::Button("Save", [this] {
    _dbManager.addNew(
    _homeControllerState.newTaskIsComplete,
    _homeControllerState.newTaskSummary,
    _homeControllerState.newTaskPriority);
    _homeControllerState.newTaskSummary = "";
    _homeControllerState.newTaskIsComplete = false;
    _homeControllerState.newTaskPriority = HomeControllerState::DEFAULT_TASK_PRIORITY;
    });
    auto newTaskLayout = ftxui::Container::Horizontal(
    {inputNewTaskSummary, newTaskCompletionStatus, newTaskPriorityDropdown, saveButton});
  4. Finalmente, más abajo en el archivo home_controller.cpp, agregue el nuevo elemento UI al auto itemListRenderer:

    inputNewTaskSummary->Render() | ftxui::flex,
    newTaskCompletionStatus->Render() | ftxui::center,
    newTaskPriorityDropdown->Render(),
    saveButton->Render(),

    Esto representa el nuevo elemento justo antes del botón Guardar en la interfaz de usuario.

3
  1. En el directorio managers, vaya a database_manager.hpp. Actualice la firma de la función addNew() para incluir el int newItemPriority que pasamos desde home_controller.cpp:

    void addNew(
    bool newItemIsComplete,
    std::string newItemSummary,
    int newItemPriority);
  2. Ahora vaya a database_manager.cpp y actualice la implementación de addNew(). Agregue int newItemProperty a los argumentos de la función:

    void DatabaseManager::addNew(
    bool newItemIsComplete,
    std::string newItemSummary,
    int newItemPriority) {
    ...implementation...
    }

    Agregue una nueva línea en la función para establecer el valor de la propiedad priority cuando guardamos Item en la base de datos:

    .priority = newItemPriority

    Su implementación addNew() ahora debería parecerse a:

    void DatabaseManager::addNew(bool newItemIsComplete, std::string newItemSummary, int newItemPriority) {
    auto item = realm::Item {
    .isComplete = newItemIsComplete,
    .summary = std::move(newItemSummary),
    .owner_id = _userId,
    .priority = newItemPriority
    };
    _database->write([&]{
    _database->add(std::move(item));
    });
    }
4

En este punto, vuelva a compilar y ejecutar la aplicación. En el directorio de compilación, reconstruya el ejecutable con los cambios realizados:

cmake --build .

Y ejecuta la aplicación:

./sync_todo /path-to-file/atlasConfig.json

Inicia sesión con la cuenta que creaste anteriormente en este tutorial. Verás el elemento que creaste. Agrega un nuevo elemento y verás que ahora puedes establecer la prioridad. Selecciona High como prioridad y guarda el elemento.

Ahora, regresa a la página de datos del Atlas en tu navegador y actualiza la Item colección. Deberías ver el nuevo elemento con el priority campo añadido y configurado como. El elemento existente no tiene 1 el priority campo.

Dos artículos en una colección
haga clic para ampliar

Nota

¿Por qué no se rompió esta sincronizar?

Añadir una propiedad a un objeto cliente del SDK no supone un cambio drástico y, por lo tanto, no requiere restablecer el cliente. La aplicación de plantilla tiene habilitado el modo de desarrollo, por lo que los cambios en el objeto cliente se reflejan automáticamente en el esquema del servidor. Para obtener más información, consulte Modo de desarrollo y Actualizar el modelo de datos.

En el archivo database_manager.cpp del directorio managers, creamos la suscripción de Sincronización Flexible que define qué documentos sincronizamos con el dispositivo y la cuenta del usuario. De forma predeterminada, nos suscribimos a todos los elementos. Puedes ver los elementos creados por otros usuarios, pero las reglas del servidor impiden escribir en ellos. Puedes ver esta lógica en el bloque donde creamos la suscripción inicial. Si no hay suscripciones al abrir la aplicación, añadimos una suscripción para todos los objetos Item:

_database->subscriptions().update([this](realm::mutable_sync_subscription_set& subs) {
// By default, we show all items.
if (!subs.find(_allItemSubscriptionName)) {
subs.add<realm::Item>(_allItemSubscriptionName);
}
}).get();

En la función toggleSubscriptions(), cambiamos la suscripción según su estado actual. En la interfaz de usuario, el usuario puede alternar entre mostrar todos los elementos o solo los suyos. Dentro de esta función, busque la lógica _myItemSubscriptionName. Si aún no existe una suscripción para este nombre, la aplicación agrega una a todos los documentos donde la propiedad owner_id coincida con el ID del usuario autenticado.

Para este tutorial, queremos mantener eso, pero solo sincronizar elementos que estén marcados como prioridad "Alta" o "Severa".

Por eso usamos un int64_t para la propiedad priority y etiquetamos los niveles de prioridad en la interfaz de usuario, de mayor a menor importancia. La prioridad más alta (grave) tiene un valor de 0 y la más baja (baja) tiene un valor de 3. Podemos hacer comparaciones directas entre un número y la propiedad de prioridad.

1

Para cambiar la suscripción, vaya al managers directorio y abra el database_manager.cpp archivo. Actualice la consulta para incluir los documentos con prioridad igual o inferior 1 a. Esto solo debe incluir elementos con prioridad "Severa" ()0 o "Alta" ().1

if (!subs.find(_myItemSubscriptionName)) {
subs.add<realm::Item>(
_myItemSubscriptionName,
[&](auto &item){
return item.owner_id == _userId && item.priority <= 1;
}
);
}
2

Ejecute la aplicación de nuevo. Inicie sesión con la cuenta que creó anteriormente en este tutorial. En el cuadro Subscription, pulse el botón Switch to Mine. Tras un momento inicial, cuando el SDK vuelva a sincronizar la colección de documentos, solo verá el nuevo elemento de alta prioridad que creó. Es posible que tenga que mover el ratón o usar las teclas de flecha para que la interfaz de usuario se vuelva a mostrar con los nuevos elementos sincronizados en segundo plano.

El documento del elemento que creó inicialmente no se muestra en el dispositivo porque no tiene el campo priority. Si desea que este elemento se sincronice con el dispositivo, puede editarlo en la interfaz de usuario de Atlas y agregar un valor al campo priority.

Tip

Cambiar suscripciones con el modo de desarrollador habilitado

En este tutorial, al cambiar la suscripción y la consulta en el campo de prioridad por primera vez, este se añade automáticamente a la sincronización de dispositivos Collection Queryable Fields. Esto se debe a que la aplicación de plantilla tiene el modo de desarrollo habilitado de forma predeterminada. Si el modo de desarrollo no estuviera habilitado, tendría que añadir manualmente el campo como consultable para usarlo en una consulta de sincronización del lado del cliente.

Para obtener más información, consulte Campos consultables.

Si desea probar la funcionalidad con más detalle, puede crear elementos con diferentes prioridades. Verá que un nuevo elemento con menor prioridad aparece brevemente en la lista de elementos y luego desaparece. El gestor de errores de sincronización proporciona un mensaje que describe este comportamiento:

A sync error occurred. Message:
"Client attempted a write that is not allowed; it has been reverted"

En este escenario, el SDK crea el elemento localmente, lo sincroniza con el backend y luego revierte la escritura porque no cumple con las reglas de suscripción.

Nota

Problema conocido de la interfaz de usuario

Si se muestra el modal de error y pasa el ratón sobre la lista de elementos en la terminal antes de cerrarlo, la representación de la interfaz de usuario se interrumpe. Esto se debe a limitaciones de la biblioteca FTXUI. Si esto ocurre, cierre la aplicación con ctrl + c y vuelva a ejecutarla. Puede evitar este problema pulsando la Dismiss tecla Intro en el modal de error antes de mover el ratón.

Agregar una propiedad a un objeto SDK existente es un cambio importante y el modo de desarrollo garantiza que el cambio de esquema se refleje en el servidor.

Nota

Compartir comentarios

¿Cómo te fue? Usa el Rate this page widget en la parte inferior derecha de la página para evaluar su efectividad. O reporta un problema en el repositorio de GitHub si tuviste algún problema.

Next

¿Qué son los servicios de aplicación Atlas?