-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
(DOCSP-36597): C++ Template App, MVC style (#197)
Add a C++ template app using FTXUI and the C++ SDK. Ignore the C++ directory when running the Bluehawk copy script. Bluehawk has a problem with using `::state:` in C++ code. For more details, refer to this issue on the Bluehawk repo: mongodb-university/Bluehawk#145 I used Bluehawk copy for all other files and manually copied the `database_manager.cpp` where the code triggering this issue is located. --------- Co-authored-by: Chris Bush <[email protected]>
- Loading branch information
Showing
62 changed files
with
2,365 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
build/ | ||
.idea/ | ||
cmake-build-debug/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
cmake_minimum_required(VERSION 3.25) | ||
|
||
project(sync_todo) | ||
|
||
set(CMAKE_CXX_STANDARD 17) | ||
|
||
Include(FetchContent) | ||
|
||
FetchContent_Declare(cpprealm | ||
GIT_REPOSITORY https://github.com/realm/realm-cpp.git | ||
GIT_TAG v1.0.0 | ||
) | ||
|
||
FetchContent_Declare(ftxui | ||
GIT_REPOSITORY https://github.com/ArthurSonzogni/ftxui | ||
GIT_TAG v5.0.0 | ||
) | ||
|
||
FetchContent_Declare(nlohmann_json | ||
GIT_REPOSITORY https://github.com/nlohmann/json.git | ||
GIT_TAG v3.11.3 | ||
) | ||
|
||
FetchContent_GetProperties(ftxui) | ||
if(NOT ftxui_POPULATED) | ||
FetchContent_Populate(ftxui) | ||
add_subdirectory(${ftxui_SOURCE_DIR} ${ftxui_BINARY_DIR} EXCLUDE_FROM_ALL) | ||
endif() | ||
|
||
FetchContent_MakeAvailable(cpprealm ftxui nlohmann_json) | ||
|
||
add_executable(sync_todo | ||
main.cpp | ||
ss.hpp | ||
controllers/app_controller.hpp | ||
controllers/app_controller.cpp | ||
controllers/controller.hpp | ||
controllers/home_controller.hpp | ||
controllers/home_controller.cpp | ||
controllers/login_controller.hpp | ||
controllers/login_controller.cpp | ||
controllers/navigation.hpp | ||
controllers/navigation.cpp | ||
managers/auth_manager.hpp | ||
managers/auth_manager.cpp | ||
managers/database_manager.hpp | ||
managers/database_manager.cpp | ||
managers/error_manager.hpp | ||
managers/error_manager.cpp | ||
state/app_config_metadata.hpp | ||
state/app_config_metadata.cpp | ||
state/app_state.hpp | ||
state/home_controller_state.hpp | ||
state/item.hpp | ||
views/scroller.hpp | ||
views/scroller.cpp | ||
) | ||
|
||
target_link_libraries(sync_todo PRIVATE cpprealm) | ||
target_link_libraries(sync_todo PRIVATE ftxui::component) | ||
target_link_libraries(sync_todo PRIVATE nlohmann_json::nlohmann_json) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
# C++ Template App | ||
|
||
> [!NOTE] | ||
> This is a Preview release of the C++ template app. | ||
A todo list application built with the [Atlas Device SDK for C++](https://www.mongodb.com/docs/realm/sdk/cpp/) and [Atlas Device Sync](https://www.mongodb.com/docs/atlas/app-services/sync/). | ||
|
||
This app uses a terminal UI built with [FTXUI](https://github.com/ArthurSonzogni/FTXUI). | ||
|
||
## Configuration | ||
|
||
For this template app to work, you must ensure that `atlasConfig.json` exists and contains the following properties: | ||
|
||
- **appId:** your Atlas App Services App ID. | ||
- **appUrl:** the URL to browse directly to your App Services App. | ||
- **baseUrl:** the App Services backend URL. This should be https://services.cloud.mongodb.com in most cases. | ||
- **clientApiBaseUrl:** the deployment region and baseURL a client application can use to connect to a specific regional | ||
deployment. This information is not used by this template app. | ||
- **dataApiBaseUrl:** the deployment region and Data API baseURL a client application can use to connect to a specific | ||
Data API app in a given region. This information is not used by this template app. | ||
- **dataExplorerLink:** the URL to browse to your collections in Atlas. Go here to see data syncing from your app. | ||
- **dataSourceName:** the name of the data source in Atlas. This information is not used by this template app. | ||
|
||
## Create an Atlas Device Sync Template App | ||
|
||
### Create the Template App using App Services CLI | ||
|
||
The easiest way to work with this client is to create the template app using App Services CLI. If you use the CLI to | ||
create the template app, or if you use the CLI to pull the C++ client you created from the App Services UI, you'll get | ||
a version of this client with the `atlasConfig.json` pre-populated with the appropriate values for your application. | ||
|
||
For more information, refer to the [Template App documentation](https://www.mongodb.com/docs/atlas/app-services/reference/template-apps/). | ||
|
||
### Cloning from GitHub | ||
|
||
If you have cloned this repository from the GitHub | ||
[mongodb/template-app-cpp-todo](https://github.com/mongodb/template-app-cpp-todo.git) | ||
repository, you must create a separate App Services App with Device Sync | ||
enabled to use this client. You can find information about how to do this | ||
in the Atlas App Services documentation page: | ||
[Template Apps -> Create a Template App](https://www.mongodb.com/docs/atlas/app-services/reference/template-apps/) | ||
|
||
Once you have created the App Services App, replace the value in this client's `appId` field | ||
in the `atlasConfig.json` file with your App Services App ID. For help finding this ID, refer | ||
to: [Find Your Project or App ID](https://www.mongodb.com/docs/atlas/app-services/reference/find-your-project-or-app-id/) | ||
|
||
### Making a Template App in the App Services UI | ||
|
||
You can create a template app by logging on to [Atlas App Services](https://services.cloud.mongodb.com) and click the | ||
**Create App From Template** button. Choose **Real Time Sync**, and then follow the prompts. | ||
|
||
You can download some of the Sync clients from the UI as a .zip file. That is not possible at this time for the C++ client. | ||
To get a copy of the C++ client with `atlasConfig.json` values pre-populated with the data for your app, pull a copy of | ||
the template app client using App Services CLI. For more information, refer to the Atlas App Services documentation page: | ||
[Template Apps -> Get a Template App Client](https://www.mongodb.com/docs/atlas/app-services/reference/template-apps/#get-a-template-app-client). | ||
|
||
## Run the app | ||
|
||
This app uses CMake to manage dependencies. You must have CMake installed to use this template app. | ||
|
||
- Make a `/build` directory inside this client directory, and `cd` into it. | ||
|
||
```shell | ||
mkdir build && cd build | ||
``` | ||
|
||
- Use CMake to create the Makefile | ||
|
||
```shell | ||
cmake ../ | ||
``` | ||
|
||
- Use CMake to build the app executable. | ||
|
||
```shell | ||
cmake --build . | ||
``` | ||
|
||
- Run the executable. Pass the path to the `atlasConfig.json` as an argument when you run the application. | ||
|
||
```shell | ||
./sync_todo /path-to-file/atlasConfig.json | ||
``` | ||
|
||
## Issues | ||
|
||
Please report issues with the template at https://github.com/mongodb-university/realm-template-apps/issues/new | ||
|
||
## Structure | ||
|
||
To see the code examples concerned with Atlas Device SDK for C++, these files are the most relevant: | ||
|
||
- Controllers: | ||
- `app_controller.cpp`: Set up app state, including reading the `atlasConfig.json` and setting up the Atlas App connection. | ||
- `home_controller.cpp`: Create the task list, add new items, and let the user change app state. | ||
- Managers | ||
- `auth_manager.cpp`: Authenticate users with the Atlas Device Sync app. | ||
- `database_manager.cpp`: Handle Device Sync client configuration, Sync subscriptions, Sync sessions, and database CRUD operations. | ||
- State | ||
- `item.hpp`: The Atlas Device SDK data model. | ||
|
||
``` | ||
├── controllers | ||
│ ├── app_controller.cpp | ||
│ ├── app_controller.hpp | ||
│ ├── controller.hpp | ||
│ ├── home_controller.cpp | ||
│ ├── home_controller.hpp | ||
│ ├── login_controller.cpp | ||
│ ├── login_controller.hpp | ||
│ ├── navigation.cpp | ||
│ └── navigation.hpp | ||
├── main.cpp | ||
├── managers | ||
│ ├── auth_manager.cpp | ||
│ ├── auth_manager.hpp | ||
│ ├── database_manager.cpp | ||
│ ├── database_manager.hpp | ||
│ ├── error_manager.cpp | ||
│ └── error_manager.hpp | ||
├── ss.hpp | ||
├── state | ||
│ ├── app_config_metadata.cpp | ||
│ ├── app_config_metadata.hpp | ||
│ ├── app_state.hpp | ||
│ ├── home_controller_state.hpp | ||
│ ├── item.hpp | ||
│ ├── offline_mode_selection.hpp | ||
│ └── subscription_selection.hpp | ||
└── views | ||
├── scroller.cpp | ||
└── scroller.hpp | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"appId": "INSERT-YOUR-APP-ID-HERE", | ||
"appUrl": "https://services.cloud.mongodb.com/groups/6388cb218e4d865c34158da5/apps/65f46bd16a5a245b65769e5d", | ||
"baseUrl": "https://services.cloud.mongodb.com", | ||
"clientApiBaseUrl": "https://us-east-1.aws.services.cloud.mongodb.com", | ||
"dataApiBaseUrl": "https://us-east-1.aws.data.mongodb-api.com", | ||
"dataExplorerLink": "https://cloud.mongodb.com/links/6388cb218e4d865c34158da5/explorer/Cluster0/database/collection/find", | ||
"dataSourceName": "mongodb-atlas" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
#include "app_controller.hpp" | ||
|
||
void AppController::onFrame() { | ||
_navigation.onFrame(); | ||
} | ||
|
||
AppController::AppController(ftxui::ScreenInteractive *screen, std::string const& pathToAtlasConfig) { | ||
_appState.screen = screen; | ||
|
||
// Read the contents of the atlasConfig.json to get the metadata for the App Services App. | ||
std::ifstream f(pathToAtlasConfig); | ||
nlohmann::json data = nlohmann::json::parse(f); | ||
auto appConfigMetadata = data.template get<AppConfigMetadata>(); | ||
f.close(); | ||
|
||
auto appConfig = realm::App::configuration { | ||
.app_id = appConfigMetadata.appId | ||
}; | ||
_appState.app = std::make_unique<realm::App>(appConfig); | ||
_appState.authManager = std::make_unique<AuthManager>(this, _appState.app.get()); | ||
_appState.errorManager = std::make_unique<ErrorManager>(this); | ||
_appState.appConfigMetadata = appConfigMetadata; | ||
|
||
// Lay out and style the error modal. | ||
auto dismissButton = ftxui::Button("Dismiss", [this]{ _appState.errorManager->clearError(); }); | ||
auto buttonLayout = ftxui::Container::Horizontal({ dismissButton }); | ||
|
||
_errorModal = Renderer(buttonLayout, [=] { | ||
auto content = ftxui::vbox({ | ||
ftxui::hbox(ftxui::text(_appState.errorManager->getError().value()) | ftxui::hcenter), | ||
ftxui::hbox(dismissButton->Render()) | ftxui::hcenter | ||
}) | ftxui::center | size(ftxui::HEIGHT, ftxui::GREATER_THAN, 10); | ||
return window( | ||
ftxui::text(L" Error "), content) | ftxui::clear_under | ftxui::center | size(ftxui::WIDTH, ftxui::GREATER_THAN, 80); | ||
}); | ||
|
||
component()->Add(_navigation.component()); | ||
|
||
if (_appState.app->get_current_user()) { | ||
_navigation.goTo(std::make_unique<HomeController>(&_appState)); | ||
} else { | ||
_navigation.goTo(std::make_unique<LoginController>(&_appState)); | ||
} | ||
} | ||
|
||
void AppController::onLoggedIn() { | ||
_navigation.goTo(std::make_unique<HomeController>(&_appState)); | ||
} | ||
|
||
void AppController::onLoggedOut() { | ||
_navigation.goTo(std::make_unique<LoginController>(&_appState)); | ||
} | ||
|
||
void AppController::onError(ErrorManager &error) { | ||
_errorModal->Detach(); | ||
component()->Add(_errorModal); | ||
_errorModal->TakeFocus(); | ||
} | ||
|
||
void AppController::onErrorCleared(ErrorManager &error) { | ||
_errorModal->Detach(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
#ifndef APP_CONTROLLER_HPP | ||
#define APP_CONTROLLER_HPP | ||
|
||
#include <nlohmann/json.hpp> | ||
#include <cpprealm/sdk.hpp> | ||
#include <fstream> | ||
|
||
#include "ftxui/component/component.hpp" | ||
#include "controller.hpp" | ||
#include "home_controller.hpp" | ||
#include "login_controller.hpp" | ||
#include "navigation.hpp" | ||
#include "../managers/auth_manager.hpp" | ||
#include "../managers/error_manager.hpp" | ||
#include "../state/app_config_metadata.hpp" | ||
#include "../state/app_state.hpp" | ||
#include "../state/home_controller_state.hpp" | ||
#include "../ss.hpp" | ||
|
||
class AppController final : public Controller, public AuthManager::Delegate, public ErrorManager::Delegate { | ||
private: | ||
AppState _appState; | ||
Navigation _navigation; | ||
ftxui::Component _errorModal; | ||
|
||
public: | ||
explicit AppController(ftxui::ScreenInteractive *screen, std::string const& pathToAtlasConfig); | ||
|
||
void onFrame() override; | ||
|
||
private: | ||
void onLoggedIn() override; | ||
|
||
void onLoggedOut() override; | ||
|
||
void onError(ErrorManager &error) override; | ||
|
||
void onErrorCleared(ErrorManager &error) override; | ||
}; | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
#ifndef CONTROLLER_HPP | ||
#define CONTROLLER_HPP | ||
|
||
#include "ftxui/component/component.hpp" | ||
|
||
class Controller { | ||
private: | ||
ftxui::Component _component; | ||
|
||
public: | ||
Controller(): Controller(ftxui::Container::Stacked({})) {} | ||
Controller(ftxui::Component component): _component(component) {} | ||
virtual ~Controller() = 0; | ||
virtual void onFrame() {} | ||
|
||
ftxui::Component component() { | ||
return _component; | ||
} | ||
}; | ||
|
||
inline Controller::~Controller() = default; | ||
|
||
#endif |
Oops, something went wrong.