Browse Source

WIP: cpp17 - dingo

cpp17-init-dingo-fail
chodak166 5 months ago
parent
commit
fc955dd1bb
  1. 10
      cpp17/lib/CMakeLists.txt
  2. 32
      cpp17/lib/include/autostore/AutoStore.h
  3. 37
      cpp17/lib/src/AutoStore.cpp
  4. 45
      cpp17/lib/src/DiContainer.cpp
  5. 102
      cpp17/lib/src/DiContainer.h
  6. 10
      cpp17/lib/src/application/presenters/StorePresenters.h
  7. 32
      cpp17/lib/src/infrastructure/helpers/Jsend.cpp
  8. 20
      cpp17/lib/src/infrastructure/helpers/Jsend.h
  9. 76
      cpp17/lib/src/infrastructure/helpers/JsonItem.cpp
  10. 22
      cpp17/lib/src/infrastructure/helpers/JsonItem.h
  11. 36
      cpp17/lib/src/infrastructure/http/HttpOrderService.cpp
  12. 20
      cpp17/lib/src/infrastructure/http/HttpOrderService.h
  13. 10
      cpp17/lib/src/infrastructure/http/HttpServer.cpp
  14. 6
      cpp17/lib/src/infrastructure/http/HttpServer.h
  15. 6
      cpp17/lib/src/webapi/controllers/StoreController.cpp
  16. 10
      cpp17/lib/src/webapi/controllers/StoreController.h
  17. 5
      cpp17/vcpkg.json

10
cpp17/lib/CMakeLists.txt

@ -5,9 +5,14 @@ set(TARGET_NAME AutoStoreLib)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Find dependencies
find_package(httplib CONFIG REQUIRED)
find_package(nlohmann_json CONFIG REQUIRED)
find_path(DINGO_INCLUDE_DIRS "dingo/allocator.h")
add_library(${TARGET_NAME} STATIC add_library(${TARGET_NAME} STATIC
src/AutoStore.cpp src/AutoStore.cpp
src/DiContainer.cpp
src/infrastructure/repositories/FileUserRepository.cpp src/infrastructure/repositories/FileUserRepository.cpp
src/infrastructure/repositories/FileItemRepository.cpp src/infrastructure/repositories/FileItemRepository.cpp
src/infrastructure/http/HttpServer.cpp src/infrastructure/http/HttpServer.cpp
@ -23,6 +28,7 @@ target_include_directories(${TARGET_NAME}
${CMAKE_CURRENT_SOURCE_DIR}/include/autostore ${CMAKE_CURRENT_SOURCE_DIR}/include/autostore
PRIVATE PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR}/src
${DINGO_INCLUDE_DIRS}
) )
target_sources(${TARGET_NAME} target_sources(${TARGET_NAME}
@ -33,9 +39,7 @@ target_sources(${TARGET_NAME}
include/autostore/AutoStore.h include/autostore/AutoStore.h
) )
# Find dependencies
find_package(httplib CONFIG REQUIRED)
find_package(nlohmann_json CONFIG REQUIRED)
target_link_libraries(${TARGET_NAME} target_link_libraries(${TARGET_NAME}
PUBLIC PUBLIC

32
cpp17/lib/include/autostore/AutoStore.h

@ -7,25 +7,14 @@
namespace nxl::autostore { namespace nxl::autostore {
// Forward declarations namespace di {
namespace application { class DiContainer;
class IItemRepository;
class IClock;
class IOrderService;
} // namespace application
namespace infrastructure {
class HttpServer;
} }
namespace webapi { namespace webapi {
class StoreController; class StoreController;
} }
namespace application {
class AddItem;
}
class AutoStore class AutoStore
{ {
public: public:
@ -38,24 +27,15 @@ public:
void stop(); void stop();
private: private:
int port;
std::string host;
std::string dataPath; std::string dataPath;
bool initialized; bool initialized;
// Dependencies
std::unique_ptr<application::IItemRepository> itemRepository;
std::unique_ptr<application::IClock> clock;
std::unique_ptr<application::IOrderService> orderService;
std::unique_ptr<application::AddItem> addItemUseCase;
std::unique_ptr<webapi::StoreController> storeController;
// HTTP server
std::unique_ptr<infrastructure::HttpServer> httpServer;
std::thread serverThread; std::thread serverThread;
bool serverRunning; bool serverRunning;
// Configuration std::unique_ptr<di::DiContainer> diContainer;
int port; std::unique_ptr<webapi::StoreController> storeController;
std::string host;
}; };
} // namespace nxl::autostore } // namespace nxl::autostore

37
cpp17/lib/src/AutoStore.cpp

@ -1,4 +1,5 @@
#include "autostore/AutoStore.h" #include "AutoStore.h"
#include "DiContainer.h"
#include "infrastructure/repositories/FileItemRepository.h" #include "infrastructure/repositories/FileItemRepository.h"
#include "infrastructure/adapters/SystemClock.h" #include "infrastructure/adapters/SystemClock.h"
#include "infrastructure/http/HttpOrderService.h" #include "infrastructure/http/HttpOrderService.h"
@ -28,27 +29,10 @@ bool AutoStore::initialize()
<< ", host: " << host << ", port: " << port << std::endl; << ", host: " << host << ", port: " << port << std::endl;
try { try {
// Create data directory if it doesn't exist
std::filesystem::create_directories(dataPath); std::filesystem::create_directories(dataPath);
// Initialize repositories and services diContainer = std::make_unique<di::DiContainer>();
std::string itemsDbPath = std::filesystem::path(dataPath) / "items.json"; storeController = std::make_unique<webapi::StoreController>(*diContainer);
itemRepository =
std::make_unique<infrastructure::FileItemRepository>(itemsDbPath);
clock = std::make_unique<infrastructure::SystemClock>();
orderService = std::make_unique<infrastructure::HttpOrderService>();
// Initialize HTTP server
httpServer = std::make_unique<infrastructure::HttpServer>(port, host);
// Initialize use case
addItemUseCase = std::make_unique<application::AddItem>(
*itemRepository, *clock, *orderService);
// Initialize store controller
storeController =
std::make_unique<webapi::StoreController>(*addItemUseCase);
initialized = true; initialized = true;
std::cout << "AutoStore initialized successfully" << std::endl; std::cout << "AutoStore initialized successfully" << std::endl;
@ -70,11 +54,10 @@ bool AutoStore::start()
std::cout << "Starting AutoStore services..." << std::endl; std::cout << "Starting AutoStore services..." << std::endl;
try { try {
// Register routes with the HTTP server auto& httpServer = diContainer->resolveRef<infrastructure::HttpServer>();
storeController->registerRoutes(httpServer->getServer()); storeController->registerRoutes(httpServer.getServer());
// Start HTTP server if (!httpServer.start(port, host)) {
if (!httpServer->start()) {
std::cerr << "Failed to start HTTP server" << std::endl; std::cerr << "Failed to start HTTP server" << std::endl;
return false; return false;
} }
@ -102,9 +85,9 @@ void AutoStore::stop()
std::cout << "Stopping AutoStore services..." << std::endl; std::cout << "Stopping AutoStore services..." << std::endl;
// Stop HTTP server if (diContainer) {
if (httpServer) { auto& httpServer = diContainer->resolveRef<infrastructure::HttpServer>();
httpServer->stop(); httpServer.stop();
} }
serverRunning = false; serverRunning = false;

45
cpp17/lib/src/DiContainer.cpp

@ -0,0 +1,45 @@
#include "DiContainer.h"
#include "infrastructure/repositories/FileItemRepository.h"
#include "infrastructure/adapters/SystemClock.h"
#include "infrastructure/http/HttpOrderService.h"
#include "infrastructure/http/HttpServer.h"
#include "application/commands/AddItem.h"
#include "webapi/controllers/StoreController.h"
#include <filesystem>
namespace nxl::autostore::di {
DiContainer::DiContainer()
{
registerDependencies();
}
void DiContainer::registerDependencies()
{
// Register shared references
container.register_type<dingo::scope<dingo::shared>,
dingo::storage<infrastructure::FileItemRepository>,
dingo::interface<application::IItemRepository>>();
container.register_type<dingo::scope<dingo::shared>,
dingo::storage<infrastructure::SystemClock>,
dingo::interface<application::IClock>>();
container.register_type<dingo::scope<dingo::shared>,
dingo::storage<infrastructure::HttpOrderService>,
dingo::interface<application::IOrderService>>();
container.register_type<dingo::scope<dingo::shared>,
dingo::storage<infrastructure::HttpServer>>();
container.register_indexed_type<dingo::scope<dingo::shared>,
dingo::storage<application::AddItem>,
dingo::interface<application::AddItem>>(
std::string("AddItem"));
// test:
auto uc = container.resolve<application::AddItem>(
std::string("AddItem")); // throws on start
}
} // namespace nxl::autostore::di

102
cpp17/lib/src/DiContainer.h

@ -0,0 +1,102 @@
#pragma once
#include <dingo/container.h>
#include <dingo/factory/constructor.h>
#include <dingo/storage/external.h>
#include <dingo/storage/shared.h>
#include <dingo/index/unordered_map.h>
#include <memory>
#include <string>
#include <filesystem>
#include <tuple>
// Forward declarations
namespace nxl::autostore {
class AutoStore;
}
namespace nxl::autostore::infrastructure {
class FileItemRepository;
class SystemClock;
class HttpOrderService;
class HttpServer;
} // namespace nxl::autostore::infrastructure
namespace nxl::autostore::application {
class AddItem;
}
namespace nxl::autostore::webapi {
class StoreController;
}
namespace nxl::autostore::di {
// Declare traits with std::string based index for named resolution
struct container_traits : dingo::dynamic_container_traits
{
using index_definition_type =
std::tuple<std::tuple<std::string, dingo::index_type::unordered_map>>;
};
/**
* @brief Dependency Injection Container for AutoStore application
*
* This class wraps the dingo container and provides a simplified interface
* for registering and resolving dependencies in the AutoStore application.
*/
class DiContainer
{
public:
/**
* @brief Construct a new DiContainer object
*/
DiContainer();
/**
* @brief Destroy the DiContainer object
*/
~DiContainer() = default;
/**
* @brief Register all application dependencies
*
* @param dataPath Path to the data directory
* @param port HTTP server port
* @param host HTTP server host
*/
void registerDependencies();
/**
* @brief Resolve a dependency by type
*
* @tparam T Type to resolve
* @return Instance of the resolved type
*/
template <typename T> T resolve() { return container.resolve<T>(); }
/**
* @brief Resolve a dependency by type as a shared pointer
*
* @tparam T Type to resolve
* @return Shared pointer to the resolved type
*/
template <typename T> std::shared_ptr<T> resolveShared()
{
return container.resolve<std::shared_ptr<T>>();
}
/**
* @brief Resolve a dependency by type as a reference
*
* @tparam T Type to resolve
* @return Reference to the resolved type
*/
template <typename T> T& resolveRef() { return container.resolve<T&>(); }
private:
dingo::container<container_traits> container;
};
} // namespace nxl::autostore::di

10
cpp17/lib/src/application/presenters/StorePresenters.h

@ -0,0 +1,10 @@
#pragma once
#include "domain/entities/Item.h"
#include <functional>
namespace nxl::autostore::application {
using ItemPresenter = std::function<void(const domain::Item& item)>;
} // namespace nxl::autostore::application

32
cpp17/lib/src/infrastructure/helpers/Jsend.cpp

@ -0,0 +1,32 @@
#include "infrastructure/helpers/Jsend.h"
namespace nxl::autostore::infrastructure {
std::string Jsend::success(const nlohmann::json& data)
{
nlohmann::json response;
response["status"] = "success";
if (!data.is_null()) {
response["data"] = data;
}
return response.dump();
}
std::string Jsend::error(const std::string& message, int code,
const nlohmann::json& data)
{
nlohmann::json response;
response["status"] = "error";
response["message"] = message;
response["code"] = code;
if (!data.is_null()) {
response["data"] = data;
}
return response.dump();
}
} // namespace nxl::autostore::infrastructure

20
cpp17/lib/src/infrastructure/helpers/Jsend.h

@ -0,0 +1,20 @@
#pragma once
#include "nlohmann/json.hpp"
#include <string>
namespace nxl::autostore::infrastructure {
class Jsend
{
public:
static std::string success(const nlohmann::json& data = nullptr);
static std::string error(const std::string& message, int code = 500,
const nlohmann::json& data = nullptr);
private:
Jsend() = delete;
~Jsend() = delete;
};
} // namespace nxl::autostore::infrastructure

76
cpp17/lib/src/infrastructure/helpers/JsonItem.cpp

@ -0,0 +1,76 @@
#include "infrastructure/helpers/JsonItem.h"
#include <chrono>
#include <ctime>
#include <stdexcept>
#include <type_traits>
namespace nxl::autostore::infrastructure {
domain::Item JsonItem::fromJson(const std::string& jsonBody)
{
auto json = nlohmann::json::parse(jsonBody);
return fromJsonObj(json);
}
domain::Item JsonItem::fromJsonObj(const nlohmann::json& j)
{
domain::Item item;
item.id = j.value("id", "");
item.name = j.value("name", "");
item.orderUrl = j.value("orderUrl", "");
item.userId = j.value("userId", "default-user");
if (j["expirationDate"].is_number()) {
// Handle numeric timestamp
time_t timestamp = j["expirationDate"];
item.expirationDate = std::chrono::system_clock::from_time_t(timestamp);
} else if (j["expirationDate"].is_string()) {
// Handle ISO 8601 string format
std::string dateStr = j["expirationDate"];
std::tm tm = {};
std::istringstream ss(dateStr);
// Parse the ISO 8601 format
ss >> std::get_time(&tm, "%Y-%m-%dT%H:%M:%S");
if (ss.fail()) {
throw std::runtime_error(
"Invalid format for expirationDate string. Expected ISO 8601 format "
"(YYYY-MM-DDTHH:MM:SS).");
}
// Convert to time_t
time_t timestamp = std::mktime(&tm);
if (timestamp == -1) {
throw std::runtime_error(
"Failed to convert expirationDate to timestamp.");
}
item.expirationDate = std::chrono::system_clock::from_time_t(timestamp);
} else {
throw std::runtime_error("Invalid type for expirationDate. Expected number "
"(Unix timestamp) or string (ISO 8601 format).");
}
if (item.name.empty()) {
throw std::runtime_error("Item name is required");
}
return item;
}
std::string JsonItem::toJson(const domain::Item& item)
{
return toJsonObj(item).dump();
}
nlohmann::json JsonItem::toJsonObj(const domain::Item& item)
{
nlohmann::json j;
j["id"] = item.id;
j["name"] = item.name;
j["expirationDate"] =
std::chrono::system_clock::to_time_t(item.expirationDate);
j["orderUrl"] = item.orderUrl;
j["userId"] = item.userId;
return j;
}
} // namespace nxl::autostore::infrastructure

22
cpp17/lib/src/infrastructure/helpers/JsonItem.h

@ -0,0 +1,22 @@
#pragma once
#include "domain/entities/Item.h"
#include "nlohmann/json.hpp"
#include <string>
namespace nxl::autostore::infrastructure {
class JsonItem
{
public:
static domain::Item fromJson(const std::string& jsonBody);
static std::string toJson(const domain::Item& item);
static nlohmann::json toJsonObj(const domain::Item& item);
static domain::Item fromJsonObj(const nlohmann::json& j);
private:
JsonItem() = delete;
~JsonItem() = delete;
};
} // namespace nxl::autostore::infrastructure

36
cpp17/lib/src/infrastructure/http/HttpOrderService.cpp

@ -0,0 +1,36 @@
#include "HttpOrderService.h"
#include <stdexcept>
#include <iostream>
namespace nxl::autostore::infrastructure {
HttpOrderService::HttpOrderService(const std::string& baseUrl)
: baseUrl(baseUrl)
{}
void HttpOrderService::orderItem(const domain::Item& item)
{
if (item.orderUrl.empty()) {
throw std::runtime_error("Order URL is empty for item: " + item.name);
}
std::string payload =
R"({"itemName": ")" + item.name + R"(", "itemId": ")" + item.id + "\"}";
sendPostRequest(item.orderUrl, payload);
}
void HttpOrderService::sendPostRequest(const std::string& url,
const std::string& payload)
{
// In a real implementation, this would use an HTTP client library
// For now, we'll simulate the HTTP call
std::cout << "POST request to: " << url << std::endl;
std::cout << "Payload: " << payload << std::endl;
// Simulate HTTP error handling
if (url.find("error") != std::string::npos) {
throw std::runtime_error("Failed to send order request to: " + url);
}
}
} // namespace nxl::autostore::infrastructure

20
cpp17/lib/src/infrastructure/http/HttpOrderService.h

@ -0,0 +1,20 @@
#pragma once
#include "application/interfaces/IOrderService.h"
#include "domain/entities/Item.h"
#include <string>
namespace nxl::autostore::infrastructure {
class HttpOrderService : public application::IOrderService
{
public:
explicit HttpOrderService(const std::string& baseUrl = "");
void orderItem(const domain::Item& item) override;
private:
std::string baseUrl;
void sendPostRequest(const std::string& url, const std::string& payload);
};
} // namespace nxl::autostore::infrastructure

10
cpp17/lib/src/infrastructure/http/HttpServer.cpp

@ -3,9 +3,7 @@
namespace nxl::autostore::infrastructure { namespace nxl::autostore::infrastructure {
HttpServer::HttpServer(int port, const std::string& host) HttpServer::HttpServer() {}
: host(host), port(port), running(false)
{}
HttpServer::~HttpServer() HttpServer::~HttpServer()
{ {
@ -14,7 +12,7 @@ HttpServer::~HttpServer()
} }
} }
bool HttpServer::start() bool HttpServer::start(int port, const std::string& host)
{ {
if (running) { if (running) {
return true; return true;
@ -47,7 +45,7 @@ bool HttpServer::start()
std::cout << "Starting HTTP server on " << host << ":" << port << std::endl; std::cout << "Starting HTTP server on " << host << ":" << port << std::endl;
// Start server in a separate thread // Start server in a separate thread
serverThread = std::thread([this]() { serverThread = std::thread([host, port, this]() {
std::cout << "Server thread started, listening on " << host << ":" << port std::cout << "Server thread started, listening on " << host << ":" << port
<< std::endl; << std::endl;
bool listenResult = server.listen(host.c_str(), port); bool listenResult = server.listen(host.c_str(), port);
@ -98,4 +96,4 @@ httplib::Server& HttpServer::getServer()
return server; return server;
} }
} // namespace nxl::autostore::infrastructure } // namespace nxl::autostore::infrastructure

6
cpp17/lib/src/infrastructure/http/HttpServer.h

@ -10,18 +10,16 @@ namespace nxl::autostore::infrastructure {
class HttpServer class HttpServer
{ {
public: public:
explicit HttpServer(int port = 8080, const std::string& host = "0.0.0.0"); explicit HttpServer();
~HttpServer(); ~HttpServer();
bool start(); bool start(int port = 8080, const std::string& host = "0.0.0.0");
void stop(); void stop();
bool isRunning() const; bool isRunning() const;
httplib::Server& getServer(); httplib::Server& getServer();
private: private:
std::string host{"0.0.0.0"};
int port{8080};
bool running{false}; bool running{false};
httplib::Server server; httplib::Server server;
std::thread serverThread; std::thread serverThread;

6
cpp17/lib/src/webapi/controllers/StoreController.cpp

@ -1,14 +1,15 @@
#include "webapi/controllers/StoreController.h" #include "webapi/controllers/StoreController.h"
#include "infrastructure/helpers/JsonItem.h" #include "infrastructure/helpers/JsonItem.h"
#include "infrastructure/helpers/Jsend.h" #include "infrastructure/helpers/Jsend.h"
#include "application/commands/AddItem.h"
namespace nxl::autostore::webapi { namespace nxl::autostore::webapi {
using infrastructure::Jsend; using infrastructure::Jsend;
using infrastructure::JsonItem; using infrastructure::JsonItem;
StoreController::StoreController(application::AddItem& addItemUseCase) StoreController::StoreController(di::DiContainer& diContainer)
: addItemUseCase(addItemUseCase) : diContainer(diContainer)
{} {}
void StoreController::registerRoutes(httplib::Server& server) void StoreController::registerRoutes(httplib::Server& server)
@ -33,6 +34,7 @@ void StoreController::addItem(const httplib::Request& req,
auto item = JsonItem::fromJson(req.body); auto item = JsonItem::fromJson(req.body);
try { try {
auto& addItemUseCase = diContainer.resolveRef<application::AddItem>();
addItemUseCase.execute(std::move(item), [&res](auto item) { addItemUseCase.execute(std::move(item), [&res](auto item) {
res.status = 201; res.status = 201;
nlohmann::json responseData = nlohmann::json::object(); nlohmann::json responseData = nlohmann::json::object();

10
cpp17/lib/src/webapi/controllers/StoreController.h

@ -1,23 +1,21 @@
#pragma once #pragma once
#include "application/commands/AddItem.h" #include "DiContainer.h"
#include "domain/entities/Item.h" #include <httplib.h> // TODO: forward declaration
#include <httplib.h>
#include <nlohmann/json.hpp>
namespace nxl::autostore::webapi { namespace nxl::autostore::webapi {
class StoreController class StoreController
{ {
public: public:
StoreController(application::AddItem& addItemUseCase); StoreController(di::DiContainer& diContainer);
void registerRoutes(httplib::Server& server); void registerRoutes(httplib::Server& server);
private: private:
void addItem(const httplib::Request& req, httplib::Response& res); void addItem(const httplib::Request& req, httplib::Response& res);
application::AddItem addItemUseCase; di::DiContainer& diContainer;
}; };
} // namespace nxl::autostore::webapi } // namespace nxl::autostore::webapi

5
cpp17/vcpkg.json

@ -3,7 +3,8 @@
"version-string": "1.0.0", "version-string": "1.0.0",
"dependencies": [ "dependencies": [
"cpp-httplib", "cpp-httplib",
"catch2", "nlohmann-json",
"nlohmann-json" "dingo",
"catch2"
] ]
} }

Loading…
Cancel
Save