Tutorial: Atlas Device Sync para C++ com FTXUI
Nesta página
- Objetivos de aprendizagem
- Pré-requisitos
- Comece com o Modelo
- Explore o aplicativo Template
- Abra o aplicativo
- Construa o Aplicativo
- Explore a estrutura do aplicativo
- Execute o aplicativo
- Verificar o Backend
- Modificar a Aplicação
- Adicionar uma nova propriedade
- Adicionar uma propriedade ao modelo
- Adicione um elemento à IU para definir a prioridade
- Salvar a nova propriedade no banco de dados
- Executar e testar
- Alterar a assinatura
- Atualizar a assinatura
- Executar e testar
- Conclusão
- O que vem a seguir?
Tempo estimado para conclusão: 30 minutos, dependendo da sua experiência com C++
O Atlas Device SDK para C++ permite armazenar e sincronizar dados entre dispositivos móveis, ardíveis ou dispositivos IoT. Este tutorial é baseado no aplicativo modelo C++ , chamado cpp.todo.flex
, que ilustra a criação de um aplicação GUI de terminal de lista de tarefas criado com FTXUI. Este aplicação permite que o usuário:
Registre seu e-mail como uma nova conta de usuário.
Faça login na conta deles com o e-mail e a senha (e saia mais tarde).
Visualize, crie, modifique e exclua suas próprias tarefas.
Visualizar todas as tarefas, mesmo onde o usuário não é o proprietário.
O aplicativo de modelo também oferece uma alternância que simula o dispositivo no "Modo Offline". Essa alternância permite que você teste rapidamente a funcionalidade Device Sync no simulador, emulando o usuário que não tem conexão com a Internet. No entanto, você provavelmente removeria essa opção em um aplicativo de produção.
Este tutorial baseia-se no aplicativo Modelo. Você adicionará um novo campo priority
ao modelo de Item
existente e atualizará a assinatura do Flexible Sync para mostrar apenas itens dentro de uma variedade de prioridades.
Objetivos de aprendizagem
Este tutorial ilustra como você pode adaptar o aplicativo modelo para suas próprias necessidades. Você não faria necessariamente esta alteração dada a estrutura atual do aplicativo modelo.
Neste tutorial, você aprenderá como:
Atualize um modelo de objetos C++ com uma alteração não interruptiva.
Atualizar uma inscrição do Device Sync.
Adicione um campo de query à configuração do Device Sync no servidor para alterar quais dados são sincronizados.
Dica
Se você preferir começar com seu próprio aplicativo em vez de seguir um tutorial guiado, confira o Início rápido do C++. Ele inclui exemplos de código copiáveis e as informações essenciais necessárias para configurar um backend do Atlas App Services.
Pré-requisitos
Certifique-se de que você tenha o software necessário instalado. O aplicativo modelo C++ pressupõe que você tenha:
CMake versão 3.25 ou mais recente.
C++ 17 ou mais recente.
Este tutorial começa com um aplicativo de modelo. Você precisa de uma conta do Atlas, de uma chave de API e do App Services CLI para criar um aplicativo modelo.
Você pode aprender mais sobre a criação de uma conta do Atlas na documentação de Comece a usar o Atlas. Para este tutorial, você precisa de uma conta do Atlas com um cluster de camada livre.
Você também precisa de uma chave de API do Atlas para a conta do MongoDB Cloud com a qual deseja se conectar. Você deve ser proprietário do projeto para criar um aplicativo modelo usando o App Services CLI.
Para saber mais sobre como instalar o App Services CLI, consulte Instalar o App Services CLI. Após instalar, execute o comando login utilizando a chave API para seu projeto Atlas.
Comece com o Modelo
Este tutorial baseia-se no aplicativo de modelo de sincronização C++ denominado cpp.todo.flex
. Começamos com o aplicativo padrão e construímos novas funcionalidades nele.
Para saber mais sobre os aplicativos de modelo, consulte Aplicativos de modelo.
Se você ainda não tiver uma conta do Atlas, cadastre-se para implantar um Aplicativo Modelo.
Siga o procedimento descrito no guia Crie uma App Services App e selecione Create App from Template. Selecione o modelo Real-time Sync . Isso cria um App Services App pré-configurado para uso com um dos clientes da aplicação do modelo do Device Sync .
Após criar um aplicativo de modelo, a interface do usuário exibe um modal rotulado Get the Front-end Code for your Template. Esse modal fornece instruções para baixar o código do cliente do aplicativo modelo como um arquivo .zip
ou usar a CLI do App Services para obter o cliente.
O aplicativo modelo C++ ainda não está disponível para download na interface do usuário do App Services. Use a CLI ou clone o repositório do Github para obter o código do cliente .
O comando appservices apps create configura o backend e cria um aplicativo de modelo C++ para você usar como base para este tutorial.
Execute o seguinte comando em uma janela de terminal para criar um aplicativo chamado "MyTutorialApp" que é implantado na região US-VA
com seu ambiente definido como "desenvolvimento" (em vez de produção ou controle de qualidade).
appservices app create \ --name MyTutorialApp \ --template cpp.todo.flex \ --deployment-model global \ --environment development
O comando cria um novo diretório no caminho atual com o mesmo nome do valor do sinalizador --name
.
Você pode bifurcar e clonar um repositório do Github que contenha o código do cliente Device Sync . O código do cliente C++ está disponível em https://github.com/mongodb/template-app-cpp-todo.
Se você usar esse processo para obter o código do cliente, deverá criar um aplicativo modelo para usar com o cliente. Siga as instruções em Crie um aplicativo modelo para usar a interface do usuário do Atlas App Services, o App Services CLI ou o Admin API para criar um aplicativo modelo do Device Sync.
Explore o aplicativo Template
Abra o aplicativo
Abra o código do cliente frontend no IDE da sua preferência.
Se você clonou o cliente de um Github repositório do , deverá inserir manualmente a do App Services App ID de Aplicativo no local apropriado em seu cliente. Siga as instruções do Configuration no cliente README.md
para saber onde inserir sua ID do aplicativo.
Construa o Aplicativo
Crie um diretório no qual construir o aplicativo. Para fins de praticidade, o
.gitignore
pacote fornecido com o aplicativo modelo ignora umbuild
diretório dentro do diretório do cliente. Navegue até o diretório de criação.mkdir build && cd build Use o CMake para criar o Makefile. Supondo que você esteja criando a partir de um diretório
build
dentro do diretório do cliente:cmake ../ Use o CMake para criar o executável do aplicativo. Isso leva alguns instantes enquanto instala as dependências e compila o executável.
cmake --build .
Explore a estrutura do aplicativo
Reserve alguns minutos para explorar como o projeto é organizado enquanto o CMake cria o executável.
Você não usará diretamente esses arquivos durante este tutorial, mas eles contêm código que demonstra o uso do C++ SDK:
arquivo | Propósito |
---|---|
controllers/app_controller.cpp | Use a biblioteca Para saber mais sobre como personalizar a configuração do seu aplicativo, consulte: Conectar-se a um backend do Atlas App Services. Este código também configura o |
managers/auth_manager.cpp | Lógica para registrar um usuário com e-mail/senha, conectá-lo ou desconectá-lo e exibir uma mensagem de erro quando ocorrerem erros de autenticação. |
Neste tutorial, você trabalhará nos seguintes arquivos:
arquivo | Propósito |
---|---|
state/item.hpp | Define o objeto Item que armazenamos no banco de dados. |
state/home_controller_state.hpp | Gerenciar o estado do aplicativo para a exibição Home. |
controllers/home_controller.hpp | Contém definições importantes para o Home view controller. |
controllers/home_controller.cpp | Implementa a visualização Home. Essa é a visualização em que um usuário conectado pode trabalhar com o aplicativo. |
managers/database_manager.hpp | Contém definições importantes para Device Sync e operações de banco de dados. |
managers/database_manager.cpp | Implementa algumas operações de banco de dados e do Device Sync, como criar itens, alterar assinaturas de queries do Device Sync e lidar com erros de sincronização. |
Execute o aplicativo
Sem fazer nenhuma alteração no código, você deve conseguir executar o aplicativo no terminal. Passe o caminho para o atlasConfig.json
como argumento ao executar o aplicativo:
./sync_todo /path-to-file/atlasConfig.json
Execute a aplicação, registre uma nova conta de usuário e, em seguida, adicione um novo item à sua lista de tarefas.
Dica
Expandir a janela do terminal, se necessário.
A parte superior da tela inicial contém uma linha de botões e um botão para ocultar tarefas concluídas. Se a janela do terminal for muito pequena, os rótulos de texto dos botões não serão exibidos. Para ver os rótulos, aumente a janela do terminal e o FTXUI vai gerar novamente o conteúdo para caber na janela maior.
Verificar o Backend
Conecte-se ao Atlas App Services. Na aba Data Services, clique em Browse Collections. Na lista de bancos de dados, localize e expanda o banco de dados do todo e, em seguida, a coleção do Item. Você deverá ver o documento que criou nesta coleção.
Modificar a Aplicação
Adicionar uma nova propriedade
Adicionar uma propriedade ao modelo
Agora que tudo está funcionando como o esperado, é possível adicionar alterações. Neste tutorial, uma propriedade priority
é adicionada a cada Item
para que os itens possam ser filtrados de acordo com prioridade.
Em um aplicativo de produção, você pode adicionar uma enumeração PriorityLevel
para restringir os valores possíveis. Neste tutorial, usaremos uma propriedade de número para simplificar o trabalho com a framework da IU.
Para fazer isso, siga estas etapas:
Abra o código do cliente em seu IDE preferido.
No diretório
state/
, abra o arquivoitem.hpp
.Adicione a seguinte propriedade à estrutura
Item
:int64_t priority; Adicione a nova propriedade
priority
aoREALM_SCHEMA()
:REALM_SCHEMA(Item, _id, isComplete, summary, owner_id, priority) O modelo
Item
agora deve ser semelhante: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
Adicione um elemento à IU para definir a prioridade
No diretório
state
, vá parahome_controller_state.hpp
. Adicione uma nova propriedadeint
sob a propriedadenewTaskIsComplete
existente. Em seguida, adicione umstatic const int
para armazenar o valor int padrão para essa propriedade.A estrutura
HomeControllerState
agora pode ser semelhante 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... }; No diretório
controllers
, acessehome_controller.hpp
. Esse controlador renderiza a exibição principal do aplicativo.Importe as bibliotecas de string e vetor:
Crie uma array de rótulos de string para o novo elemento de prioridade da IU:
std::vector<std::string> priorityLevelLabels = { "Severe", "High", "Medium", "Low" }; Ainda no diretório
controllers
, vá parahome_controller.cpp
. É aqui que adicionamos um elemento de IU para permitir que o usuário defina a prioridade do item. O FTXUI oferece dois elementos de IU que você pode usar para essa funcionalidade:Radiobox
ouDropdown
. Neste tutorial, usaremosDropdown
, mas talvez você prefiraRadiobox
se não gostar da maneira como a IU reflui para renderizar a lista suspensa.Adicione esta nova entrada de elemento de IU após a linha
auto newTaskCompletionStatus
:auto newTaskPriorityDropdown = ftxui::Dropdown( &priorityLevelLabels, &_homeControllerState.newTaskPriority ); No fechamento da função
auto saveButton
, passe a seleção de prioridade da tarefa para a chamada de função_dbManager.addNew()
:_dbManager.addNew( _homeControllerState.newTaskIsComplete, _homeControllerState.newTaskSummary, _homeControllerState.newTaskPriority); Em seguida, adicione uma linha para redefinir a seleção de prioridade com o valor padrão:
_homeControllerState.newTaskPriority = HomeControllerState::DEFAULT_TASK_PRIORITY; Adicione o seletor suspenso ao
auto newTaskLayout
, que define o layout dos elementos interativos no contêiner da linha do item:auto newTaskLayout = ftxui::Container::Horizontal( {inputNewTaskSummary, newTaskCompletionStatus, newTaskPriorityDropdown, saveButton}); Esta seção do seu código agora deve ser semelhante 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}); Por último, mais para o fim do arquivo
home_controller.cpp
, adicione o novo elemento de IU aoauto itemListRenderer
:inputNewTaskSummary->Render() | ftxui::flex, newTaskCompletionStatus->Render() | ftxui::center, newTaskPriorityDropdown->Render(), saveButton->Render(), Isso renderiza o novo elemento logo antes do botão Salvar na IU.
Salvar a nova propriedade no banco de dados
No diretório
managers
, acessedatabase_manager.hpp
. Atualize a assinatura da funçãoaddNew()
para incluir oint newItemPriority
que passamos dehome_controller.cpp
:void addNew( bool newItemIsComplete, std::string newItemSummary, int newItemPriority); Agora acesse
database_manager.cpp
e atualize a implementação deaddNew()
. Adicioneint newItemProperty
aos argumentos da função:void DatabaseManager::addNew( bool newItemIsComplete, std::string newItemSummary, int newItemPriority) { ...implementation... } Adicione uma nova linha na função para definir o valor da propriedade
priority
quando salvamosItem
no banco de dados:.priority = newItemPriority Sua implementação
addNew()
agora deve ser semelhante 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)); }); }
Executar e testar
Nesse ponto, crie e execute o aplicativo novamente. No diretório de compilação, recrie o executável com as alterações feitas:
cmake --build .
E execute o aplicativo:
./sync_todo /path-to-file/atlasConfig.json
Faça login usando a conta que você criou neste tutorial. Você verá o único item que criou anteriormente. Adicione um novo item e você verá que agora pode definir a prioridade. Escolha High
para a prioridade e salve o item.
Agora volte para a página de dados do Atlas em seu navegador e atualize a coleção do Item
. Você deve agora visualizar o novo Item com o campo priority
adicionado e configurado para 1. O item existente não tem um campo priority
.
Observação
Por que isso não interrompeu a sincronização?
Adicionar uma propriedade a um objeto cliente SDK não é uma alteração interruptiva e, portanto, não requer um reinício do cliente. O aplicativo de modelo tem o modo de desenvolvimento habilitado, portanto, as alterações no objeto cliente são refletidas automaticamente no esquema do lado do servidor. Para obter mais informações, consulte Modo de desenvolvimento e Atualizar seu modelo de dados.
Alterar a assinatura
No arquivo database_manager.cpp
no diretório managers
, criamos a assinatura do Flexible Sync que define quais documentos sincronizamos com o dispositivo e a conta do usuário. Por padrão, assinamos todos os itens. Você pode ver os itens que outras pessoas criam, mas as regras do lado do servidor impedem que você grave neles. Você pode ver essa lógica no bloco em que criamos a assinatura inicial. Se não houver assinaturas quando o aplicativo for aberto, adicionaremos uma assinatura para todos os 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();
Na função toggleSubscriptions()
, trocamos a assinatura, dependendo do estado da assinatura atual. Na UI, o usuário pode alternar entre mostrar todos os itens ou mostrar apenas seus próprios itens. Dentro desta função, encontre a lógica _myItemSubscriptionName
. Se ainda não houver uma assinatura para este nome de assinatura , o aplicativo adicionará uma assinatura a todos os documentos em que a propriedade owner_id
corresponder ao ID do usuário autenticado.
Neste tutorial, queremos manter isso, mas apenas sincronizar itens marcados como prioridade "High" (alta) ou "Severe" (grave).
É por isso que usamos um int64_t
para a propriedade priority
e rotulamos os níveis de prioridade na IU de mais a menos importante. A prioridade mais alta (grave) tem o valor 0 e a prioridade mais baixa (baixa) tem o valor 3. Podemos fazer comparações diretas entre um número e a propriedade prioritária.
Atualizar a assinatura
Para alterar a assinatura, acesse o diretório managers
e abra o arquivo database_manager.cpp
. Atualize a consulta para incluir documentos cuja prioridade seja igual ou menor que 1. Isso deve incluir apenas itens de prioridade "Severe" (0) ou "High" (1).
if (!subs.find(_myItemSubscriptionName)) { subs.add<realm::Item>( _myItemSubscriptionName, [&](auto &item){ return item.owner_id == _userId && item.priority <= 1; } ); }
Executar e testar
Execute o aplicativo novamente. Faça login usando a conta que você criou neste tutorial. Na caixa Subscription
, pressione a opção Switch to
Mine
. Após um momento inicial em que o SDK ressincroniza a coleção de documentos, você verá apenas o novo item de alta prioridade que você criou. Talvez seja necessário mover o mouse ou usar a tecla de seta para fazer com que a interface do usuário seja renderizada novamente com os novos itens que foram sincronizados em segundo plano.
O documento Item que você criou inicialmente não é exibido no dispositivo, porque ele não tem um campo priority
. Se quiser que esse item seja sincronizado com o dispositivo, você pode editar o documento na interface do usuário do Atlas e adicionar um valor para o campo priority
.
Dica
Alterando assinaturas com o modo de desenvolvedor ativado
Neste tutorial, quando você altera a assinatura e a query no campo de prioridade pela primeira vez, o campo é adicionado automaticamente ao Device Sync Collection Queryable Fields. Isso ocorre porque o aplicativo de modelo tem o Modo de Desenvolvimento habilitado por padrão. Se o Modo de Desenvolvimento não estivesse habilitado, você teria que adicionar manualmente o campo como um campo consultável para usá-lo em uma query de sincronização do lado do cliente.
Para obter mais informações, consulte Campos consultáveis.
Se quiser testar ainda mais a funcionalidade, crie Itens de várias prioridades. Você verá um novo item com uma prioridade mais baixa aparecer brevemente na lista de itens e depois desaparecer. O manipulador de erros de sincronização fornece uma mensagem que descreve esse comportamento:
A sync error occurred. Message: "Client attempted a write that is not allowed; it has been reverted"
Nesse cenário, o SDK cria o Item localmente, sincroniza com o backend e, em seguida, reverte a gravação porque ele não atende às regras de assinatura.
Observação
Problema conhecido de IU
Se o modal de erro for exibido e você mover o mouse sobre a lista de itens no terminal antes de descartar o modal de erro, a renderização da IU será interrompida. Isso está relacionado às limitações da biblioteca FTXUI. Se isso ocorrer, feche o aplicativo usando ctrl + c
e execute-o novamente. Você pode evitar esse problema usando a tecla enter para pressionar o botão Dismiss
no modal de erro antes de mover o mouse.
Conclusão
Adicionar uma propriedade a um objeto de SDK existente é uma alteração não interruptiva, e o modo de desenvolvimento garante que a alteração de esquema se reflita no lado do servidor.
O que vem a seguir?
Leia nossa documentação do C++ SDK.
Encontre postagens de blog orientadas para desenvolvedores e tutoriais de integração no MongoDB Developer Hub.
Participe do Fórum da MongoDB Community para aprender com outros desenvolvedores e especialistas técnicos do MongoDB.
Explore exemplos de projetos de engenharia fornecidos por especialistas.
Observação
Compartilhar feedback
Como foi? Use o widget Rate this page no canto inferior direito da página para avaliar sua eficácia. Ou registre um problema no repositório GitHub se você teve algum problema.