Browse Source

WIP: cpp17

cpp17-init-dingo-fail
chodak166 5 months ago
parent
commit
a6d835d48f
  1. 10
      cpp17/CMakePresets.json
  2. 4
      cpp17/lib/CMakeLists.txt
  3. 17
      cpp17/lib/include/autostore/AutoStore.h
  4. 24
      cpp17/lib/src/AutoStore.cpp
  5. 8
      cpp17/lib/src/application/commands/AddItem.cpp
  6. 12
      cpp17/lib/src/application/commands/AddItem.h
  7. 2
      cpp17/lib/src/application/interfaces/IItemRepository.h
  8. 1
      cpp17/lib/src/domain/entities/Item.h
  9. 36
      cpp17/lib/src/infrastructure/adapters/HttpOrderService.cpp
  10. 20
      cpp17/lib/src/infrastructure/adapters/HttpOrderService.h
  11. 6
      cpp17/lib/src/infrastructure/http/HttpServer.h
  12. 45
      cpp17/lib/src/infrastructure/repositories/FileItemRepository.cpp
  13. 2
      cpp17/lib/src/infrastructure/repositories/FileItemRepository.h
  14. 109
      cpp17/lib/src/webapi/controllers/StoreController.cpp
  15. 11
      cpp17/lib/src/webapi/controllers/StoreController.h

10
cpp17/CMakePresets.json

@ -5,8 +5,16 @@
"name": "default",
"toolchainFile": "${env:VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_EXPORT_COMPILE_COMMANDS": "TRUE"
}
}
],
"buildPresets": [
{
"name": "default",
"configurePreset": "default",
"jobs": 8
}
]
}
}

4
cpp17/lib/CMakeLists.txt

@ -10,8 +10,10 @@ add_library(${TARGET_NAME} STATIC
src/AutoStore.cpp
src/infrastructure/repositories/FileUserRepository.cpp
src/infrastructure/repositories/FileItemRepository.cpp
src/infrastructure/adapters/HttpOrderService.cpp
src/infrastructure/http/HttpServer.cpp
src/infrastructure/http/HttpOrderService.cpp
src/infrastructure/helpers/Jsend.cpp
src/infrastructure/helpers/JsonItem.cpp
src/webapi/controllers/StoreController.cpp
src/application/commands/AddItem.cpp
)

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

@ -22,19 +22,19 @@ namespace webapi {
class StoreController;
}
namespace application {
class AddItem;
}
class AutoStore
{
public:
explicit AutoStore(std::string_view dataPath);
AutoStore(std::string_view dataPath, int port = 8080,
std::string_view host = "0.0.0.0");
~AutoStore();
// Initialize the application
bool initialize();
// Start the application services
bool start();
// Stop the application services
void stop();
private:
@ -45,12 +45,17 @@ private:
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;
bool serverRunning;
// Configuration
int port;
std::string host;
};
} // namespace nxl::autostore

24
cpp17/lib/src/AutoStore.cpp

@ -1,7 +1,7 @@
#include "autostore/AutoStore.h"
#include "infrastructure/repositories/FileItemRepository.h"
#include "infrastructure/adapters/SystemClock.h"
#include "infrastructure/adapters/HttpOrderService.h"
#include "infrastructure/http/HttpOrderService.h"
#include "webapi/controllers/StoreController.h"
#include "infrastructure/http/HttpServer.h"
#include <iostream>
@ -10,8 +10,9 @@
namespace nxl::autostore {
AutoStore::AutoStore(std::string_view dataPath)
: dataPath(dataPath), initialized(false), serverRunning(false)
AutoStore::AutoStore(std::string_view dataPath, int port, std::string_view host)
: dataPath(dataPath), port(port), host(host), initialized(false),
serverRunning(false)
{}
AutoStore::~AutoStore()
@ -24,7 +25,7 @@ AutoStore::~AutoStore()
bool AutoStore::initialize()
{
std::cout << "Initializing AutoStore with data path: " << dataPath
<< std::endl;
<< ", host: " << host << ", port: " << port << std::endl;
try {
// Create data directory if it doesn't exist
@ -39,12 +40,16 @@ bool AutoStore::initialize()
orderService = std::make_unique<infrastructure::HttpOrderService>();
// Initialize HTTP server
httpServer = std::make_unique<infrastructure::HttpServer>(8080, "0.0.0.0");
httpServer = std::make_unique<infrastructure::HttpServer>(port, host);
// Initialize store controller
storeController = std::make_unique<webapi::StoreController>(
// Initialize use case
addItemUseCase = std::make_unique<application::AddItem>(
*itemRepository, *clock, *orderService);
// Initialize store controller
storeController =
std::make_unique<webapi::StoreController>(*addItemUseCase);
initialized = true;
std::cout << "AutoStore initialized successfully" << std::endl;
return true;
@ -76,9 +81,10 @@ bool AutoStore::start()
serverRunning = true;
std::cout << "AutoStore services started successfully" << std::endl;
std::cout << "HTTP server listening on http://0.0.0.0:8080" << std::endl;
std::cout << "API endpoint: POST http://0.0.0.0:8080/api/items"
std::cout << "HTTP server listening on http://" << host << ":" << port
<< std::endl;
std::cout << "API endpoint: POST http://" << host << ":" << port
<< "/api/items" << std::endl;
return true;
} catch (const std::exception& e) {

8
cpp17/lib/src/application/commands/AddItem.cpp

@ -8,7 +8,7 @@ AddItem::AddItem(IItemRepository& itemRepository, IClock& clock,
: itemRepository(itemRepository), clock(clock), orderService(orderService)
{}
void AddItem::execute(domain::Item&& item, const IntPresenter& presenter)
void AddItem::execute(domain::Item&& item, const ItemPresenter& presenter)
{
try {
const auto currentTime = clock.getCurrentTime();
@ -17,10 +17,10 @@ void AddItem::execute(domain::Item&& item, const IntPresenter& presenter)
orderService.orderItem(item);
}
itemRepository.save(item);
presenter(1); // Success
item.id = itemRepository.save(item);
presenter(item); // Success
} catch (const std::exception& e) {
presenter(0); // Failure
presenter(item); // Failure
}
}

12
cpp17/lib/src/application/commands/AddItem.h

@ -5,11 +5,9 @@
#include "application/interfaces/IItemRepository.h"
#include "application/interfaces/IClock.h"
#include "application/interfaces/IOrderService.h"
#include "application/presenters/GenericPresenters.h"
#include "application/presenters/StorePresenters.h"
namespace nxl {
namespace autostore {
namespace application {
namespace nxl::autostore::application {
class AddItem
{
@ -18,7 +16,7 @@ public:
AddItem(IItemRepository& itemRepository, IClock& clock,
IOrderService& orderService);
void execute(domain::Item&& item, const IntPresenter& presenter);
void execute(domain::Item&& item, const ItemPresenter& presenter);
private:
IItemRepository& itemRepository;
@ -27,6 +25,4 @@ private:
domain::ItemExpirationPolicy expirationPolicy;
};
} // namespace application
} // namespace autostore
} // namespace nxl
} // namespace nxl::autostore::application

2
cpp17/lib/src/application/interfaces/IItemRepository.h

@ -12,7 +12,7 @@ class IItemRepository
{
public:
virtual ~IItemRepository() = default;
virtual void save(const domain::Item& item) = 0;
virtual domain::Item::Id_t save(const domain::Item& item) = 0;
virtual std::optional<domain::Item> findById(std::string_view id) = 0;
virtual std::vector<domain::Item> findByUser(std::string_view userId) = 0;
virtual std::vector<domain::Item> findAll() = 0;

1
cpp17/lib/src/domain/entities/Item.h

@ -9,6 +9,7 @@ namespace nxl::autostore::domain {
struct Item
{
using Id_t = std::string;
inline const static Id_t NULL_ID{""};
Id_t id;
std::string name;
std::chrono::system_clock::time_point expirationDate;

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

@ -1,36 +0,0 @@
#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/adapters/HttpOrderService.h

@ -1,20 +0,0 @@
#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

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

@ -20,9 +20,9 @@ public:
httplib::Server& getServer();
private:
std::string host;
int port;
bool running;
std::string host{"0.0.0.0"};
int port{8080};
bool running{false};
httplib::Server server;
std::thread serverThread;
};

45
cpp17/lib/src/infrastructure/repositories/FileItemRepository.cpp

@ -1,5 +1,5 @@
#include "infrastructure/repositories/FileItemRepository.h"
#include "nlohmann/json.hpp"
#include "infrastructure/helpers/JsonItem.h"
#include <fstream>
#include <algorithm>
#include <chrono>
@ -10,37 +10,12 @@ namespace nxl::autostore::infrastructure {
namespace {
// Helper functions for JSON serialization
inline void itemToJson(nlohmann::json& j, const domain::Item& item)
{
j =
nlohmann::json{{"id", item.id},
{"name", item.name},
{"expirationDate",
std::chrono::system_clock::to_time_t(item.expirationDate)},
{"orderUrl", item.orderUrl},
{"userId", item.userId}};
}
inline void jsonToItem(const nlohmann::json& j, domain::Item& item)
{
j.at("id").get_to(item.id);
j.at("name").get_to(item.name);
std::time_t expirationTime;
j.at("expirationDate").get_to(expirationTime);
item.expirationDate = std::chrono::system_clock::from_time_t(expirationTime);
j.at("orderUrl").get_to(item.orderUrl);
j.at("userId").get_to(item.userId);
}
// Helper functions for vector serialization
inline nlohmann::json itemsToJson(const std::vector<domain::Item>& items)
{
nlohmann::json j = nlohmann::json::array();
for (const auto& item : items) {
nlohmann::json itemJson;
itemToJson(itemJson, item);
j.push_back(itemJson);
j.push_back(infrastructure::JsonItem::toJsonObj(item));
}
return j;
}
@ -49,9 +24,7 @@ inline std::vector<domain::Item> jsonToItems(const nlohmann::json& j)
{
std::vector<domain::Item> items;
for (const auto& itemJson : j) {
domain::Item item;
jsonToItem(itemJson, item);
items.push_back(item);
items.push_back(infrastructure::JsonItem::fromJsonObj(itemJson));
}
return items;
}
@ -63,9 +36,10 @@ FileItemRepository::FileItemRepository(std::string_view dbPath) : dbPath(dbPath)
load();
}
void FileItemRepository::save(const domain::Item& item)
domain::Item::Id_t FileItemRepository::save(const domain::Item& item)
{
std::lock_guard<std::mutex> lock(mtx);
domain::Item::Id_t id = item.id;
auto it =
std::find_if(items.begin(), items.end(),
[&](const domain::Item& i) { return i.id == item.id; });
@ -73,9 +47,16 @@ void FileItemRepository::save(const domain::Item& item)
if (it != items.end()) {
*it = item;
} else {
items.push_back(item);
domain::Item newItem{item};
newItem.id = "item-"
+ std::to_string(
std::chrono::system_clock::now().time_since_epoch().count());
items.push_back(newItem);
id = newItem.id;
}
persist();
return id;
}
std::optional<domain::Item> FileItemRepository::findById(std::string_view id)

2
cpp17/lib/src/infrastructure/repositories/FileItemRepository.h

@ -11,7 +11,7 @@ class FileItemRepository : public application::IItemRepository
{
public:
explicit FileItemRepository(std::string_view dbPath);
void save(const domain::Item& item) override;
domain::Item::Id_t save(const domain::Item& item) override;
std::optional<domain::Item> findById(std::string_view id) override;
std::vector<domain::Item> findByUser(std::string_view userId) override;
std::vector<domain::Item> findAll() override;

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

@ -1,15 +1,14 @@
#include "webapi/controllers/StoreController.h"
#include <chrono>
#include <ctime>
#include <iomanip>
#include <sstream>
#include "infrastructure/helpers/JsonItem.h"
#include "infrastructure/helpers/Jsend.h"
namespace nxl::autostore::webapi {
StoreController::StoreController(application::IItemRepository& itemRepository,
application::IClock& clock,
application::IOrderService& orderService)
: addItemUseCase(itemRepository, clock, orderService)
using infrastructure::Jsend;
using infrastructure::JsonItem;
StoreController::StoreController(application::AddItem& addItemUseCase)
: addItemUseCase(addItemUseCase)
{}
void StoreController::registerRoutes(httplib::Server& server)
@ -26,96 +25,32 @@ void StoreController::addItem(const httplib::Request& req,
try {
if (req.body.empty()) {
res.status = 400;
res.set_content(createErrorResponse("Request body is empty"),
res.set_content(Jsend::error("Request body is empty", 400),
"application/json");
return;
}
auto item = parseItemFromJson(req.body);
auto item = JsonItem::fromJson(req.body);
// Execute the use case with a simple presenter
bool success = false;
addItemUseCase.execute(std::move(item),
[&success](int result) { success = (result == 1); });
try {
addItemUseCase.execute(std::move(item), [&res](auto item) {
res.status = 201;
nlohmann::json responseData = nlohmann::json::object();
responseData["id"] = item.id;
res.set_content(Jsend::success(responseData), "application/json");
});
if (success) {
res.status = 201;
res.set_content(createSuccessResponse(item), "application/json");
} else {
} catch (const std::exception& e) {
res.status = 500;
res.set_content(createErrorResponse("Failed to add item"),
"application/json");
res.set_content(
Jsend::error("Failed to add item: " + std::string(e.what()),
res.status),
"application/json");
}
} catch (const std::exception& e) {
res.status = 400;
res.set_content(createErrorResponse(e.what()), "application/json");
}
}
domain::Item StoreController::parseItemFromJson(const std::string& jsonBody)
{
auto json = nlohmann::json::parse(jsonBody);
domain::Item item;
item.id = json.value("id", "");
item.name = json.value("name", "");
item.orderUrl = json.value("orderUrl", "");
item.userId = json.value("userId", "default-user");
// Parse expiration date
if (json.contains("expirationDate")) {
std::string dateStr = json["expirationDate"];
std::tm tm = {};
std::istringstream ss(dateStr);
ss >> std::get_time(&tm, "%Y-%m-%dT%H:%M:%S");
if (ss.fail()) {
throw std::runtime_error("Invalid expiration date format. Use ISO 8601 "
"format: YYYY-MM-DDTHH:MM:SS");
}
item.expirationDate =
std::chrono::system_clock::from_time_t(std::mktime(&tm));
} else {
// Default to 24 hours from now
item.expirationDate =
std::chrono::system_clock::now() + std::chrono::hours(24);
}
if (item.id.empty()) {
// Generate a simple ID if not provided
item.id = "item-"
+ std::to_string(
std::chrono::system_clock::now().time_since_epoch().count());
res.set_content(Jsend::error(e.what(), res.status), "application/json");
}
if (item.name.empty()) {
throw std::runtime_error("Item name is required");
}
return item;
}
std::string StoreController::createSuccessResponse(const domain::Item& item)
{
nlohmann::json response;
response["success"] = true;
response["message"] = "Item added successfully";
response["item"]["id"] = item.id;
response["item"]["name"] = item.name;
response["item"]["expirationDate"] =
std::chrono::system_clock::to_time_t(item.expirationDate);
response["item"]["orderUrl"] = item.orderUrl;
response["item"]["userId"] = item.userId;
return response.dump();
}
std::string StoreController::createErrorResponse(const std::string& message)
{
nlohmann::json response;
response["success"] = false;
response["message"] = message;
return response.dump();
}
} // namespace nxl::autostore::webapi

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

@ -1,9 +1,6 @@
#pragma once
#include "application/commands/AddItem.h"
#include "application/interfaces/IItemRepository.h"
#include "application/interfaces/IClock.h"
#include "application/interfaces/IOrderService.h"
#include "domain/entities/Item.h"
#include <httplib.h>
#include <nlohmann/json.hpp>
@ -13,19 +10,13 @@ namespace nxl::autostore::webapi {
class StoreController
{
public:
StoreController(application::IItemRepository& itemRepository,
application::IClock& clock,
application::IOrderService& orderService);
StoreController(application::AddItem& addItemUseCase);
void registerRoutes(httplib::Server& server);
private:
void addItem(const httplib::Request& req, httplib::Response& res);
domain::Item parseItemFromJson(const std::string& jsonBody);
std::string createSuccessResponse(const domain::Item& item);
std::string createErrorResponse(const std::string& message);
application::AddItem addItemUseCase;
};

Loading…
Cancel
Save