Browse Source

WIP: cpp17

cpp17-init-dingo-fail
chodak166 5 months ago
parent
commit
15da327b15
  1. 4
      cpp17/lib/CMakeLists.txt
  2. 29
      cpp17/lib/include/autostore/AutoStore.h
  3. 77
      cpp17/lib/src/AutoStore.cpp
  4. 101
      cpp17/lib/src/infrastructure/http/HttpServer.cpp
  5. 30
      cpp17/lib/src/infrastructure/http/HttpServer.h
  6. 121
      cpp17/lib/src/webapi/controllers/StoreController.cpp
  7. 32
      cpp17/lib/src/webapi/controllers/StoreController.h

4
cpp17/lib/CMakeLists.txt

@ -10,6 +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/webapi/controllers/StoreController.cpp
src/application/commands/AddItem.cpp
)
target_include_directories(${TARGET_NAME}

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

@ -3,14 +3,30 @@
#include <memory>
#include <string>
#include <string_view>
#include <thread>
namespace nxl::autostore {
// Forward declarations
namespace application {
class IItemRepository;
class IClock;
class IOrderService;
} // namespace application
namespace infrastructure {
class HttpServer;
}
namespace webapi {
class StoreController;
}
class AutoStore
{
public:
explicit AutoStore(std::string_view dataPath);
~AutoStore() = default;
~AutoStore();
// Initialize the application
bool initialize();
@ -24,6 +40,17 @@ public:
private:
std::string dataPath;
bool initialized;
// Dependencies
std::unique_ptr<application::IItemRepository> itemRepository;
std::unique_ptr<application::IClock> clock;
std::unique_ptr<application::IOrderService> orderService;
std::unique_ptr<webapi::StoreController> storeController;
// HTTP server
std::unique_ptr<infrastructure::HttpServer> httpServer;
std::thread serverThread;
bool serverRunning;
};
} // namespace nxl::autostore

77
cpp17/lib/src/AutoStore.cpp

@ -1,21 +1,57 @@
#include "autostore/AutoStore.h"
#include "infrastructure/repositories/FileItemRepository.h"
#include "infrastructure/adapters/SystemClock.h"
#include "infrastructure/adapters/HttpOrderService.h"
#include "webapi/controllers/StoreController.h"
#include "infrastructure/http/HttpServer.h"
#include <iostream>
#include <filesystem>
#include <memory>
namespace nxl::autostore {
AutoStore::AutoStore(std::string_view dataPath)
: dataPath(dataPath), initialized(false)
: dataPath(dataPath), initialized(false), serverRunning(false)
{}
AutoStore::~AutoStore()
{
if (serverRunning) {
stop();
}
}
bool AutoStore::initialize()
{
// TODO: Initialize repositories and services
std::cout << "Initializing AutoStore with data path: " << dataPath
<< std::endl;
// For now, just mark as initialized
try {
// Create data directory if it doesn't exist
std::filesystem::create_directories(dataPath);
// Initialize repositories and services
std::string itemsDbPath = std::filesystem::path(dataPath) / "items.json";
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>(8080, "0.0.0.0");
// Initialize store controller
storeController = std::make_unique<webapi::StoreController>(
*itemRepository, *clock, *orderService);
initialized = true;
std::cout << "AutoStore initialized successfully" << std::endl;
return true;
} catch (const std::exception& e) {
std::cerr << "Failed to initialize AutoStore: " << e.what() << std::endl;
return false;
}
}
bool AutoStore::start()
@ -26,16 +62,47 @@ bool AutoStore::start()
return false;
}
// TODO: Start background services, HTTP server, etc.
std::cout << "Starting AutoStore services..." << std::endl;
try {
// Register routes with the HTTP server
storeController->registerRoutes(httpServer->getServer());
// Start HTTP server
if (!httpServer->start()) {
std::cerr << "Failed to start HTTP server" << std::endl;
return false;
}
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::endl;
return true;
} catch (const std::exception& e) {
std::cerr << "Failed to start AutoStore services: " << e.what()
<< std::endl;
return false;
}
}
void AutoStore::stop()
{
// TODO: Stop all services
if (!serverRunning) {
return;
}
std::cout << "Stopping AutoStore services..." << std::endl;
// Stop HTTP server
if (httpServer) {
httpServer->stop();
}
serverRunning = false;
std::cout << "AutoStore services stopped" << std::endl;
}
} // namespace nxl::autostore

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

@ -0,0 +1,101 @@
#include "infrastructure/http/HttpServer.h"
#include <iostream>
namespace nxl::autostore::infrastructure {
HttpServer::HttpServer(int port, const std::string& host)
: host(host), port(port), running(false)
{}
HttpServer::~HttpServer()
{
if (running) {
stop();
}
}
bool HttpServer::start()
{
if (running) {
return true;
}
// Set up error handler
server.set_error_handler([](const auto& req, auto& res) {
auto fmt = "<p>Error Status: <span style='color:red;'>%d</span></p>";
char buf[BUFSIZ];
snprintf(buf, sizeof(buf), fmt, res.status);
res.set_content(buf, "text/html");
});
// Set up exception handler
server.set_exception_handler(
[](const auto& req, auto& res, std::exception_ptr ep) {
auto fmt = "<h1>Error 500</h1><p>%s</p>";
char buf[BUFSIZ];
try {
std::rethrow_exception(ep);
} catch (std::exception& e) {
snprintf(buf, sizeof(buf), fmt, e.what());
} catch (...) {
snprintf(buf, sizeof(buf), fmt, "Unknown Exception");
}
res.set_content(buf, "text/html");
res.status = 500;
});
std::cout << "Starting HTTP server on " << host << ":" << port << std::endl;
// Start server in a separate thread
serverThread = std::thread([this]() {
std::cout << "Server thread started, listening on " << host << ":" << port
<< std::endl;
bool listenResult = server.listen(host.c_str(), port);
std::cout << "Server stopped, listen result: " << listenResult << std::endl;
});
// Give the server a moment to start
std::this_thread::sleep_for(std::chrono::milliseconds(500));
// Check if server is listening by trying to bind to the port
if (!server.is_running()) {
std::cerr << "Failed to start HTTP server - server is not running"
<< std::endl;
if (serverThread.joinable()) {
serverThread.join();
}
return false;
}
running = true;
std::cout << "HTTP server is running" << std::endl;
return true;
}
void HttpServer::stop()
{
if (!running) {
return;
}
std::cout << "Stopping HTTP server..." << std::endl;
server.stop();
// Wait for the server to stop
std::this_thread::sleep_for(std::chrono::milliseconds(500));
running = false;
std::cout << "HTTP server stopped" << std::endl;
}
bool HttpServer::isRunning() const
{
return running;
}
httplib::Server& HttpServer::getServer()
{
return server;
}
} // namespace nxl::autostore::infrastructure

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

@ -0,0 +1,30 @@
#pragma once
#include <httplib.h>
#include <memory>
#include <string>
#include <thread>
namespace nxl::autostore::infrastructure {
class HttpServer
{
public:
explicit HttpServer(int port = 8080, const std::string& host = "0.0.0.0");
~HttpServer();
bool start();
void stop();
bool isRunning() const;
httplib::Server& getServer();
private:
std::string host;
int port;
bool running;
httplib::Server server;
std::thread serverThread;
};
} // namespace nxl::autostore::infrastructure

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

@ -0,0 +1,121 @@
#include "webapi/controllers/StoreController.h"
#include <chrono>
#include <ctime>
#include <iomanip>
#include <sstream>
namespace nxl::autostore::webapi {
StoreController::StoreController(application::IItemRepository& itemRepository,
application::IClock& clock,
application::IOrderService& orderService)
: addItemUseCase(itemRepository, clock, orderService)
{}
void StoreController::registerRoutes(httplib::Server& server)
{
server.Post("/api/items",
[this](const httplib::Request& req, httplib::Response& res) {
this->addItem(req, res);
});
}
void StoreController::addItem(const httplib::Request& req,
httplib::Response& res)
{
try {
if (req.body.empty()) {
res.status = 400;
res.set_content(createErrorResponse("Request body is empty"),
"application/json");
return;
}
auto item = parseItemFromJson(req.body);
// Execute the use case with a simple presenter
bool success = false;
addItemUseCase.execute(std::move(item),
[&success](int result) { success = (result == 1); });
if (success) {
res.status = 201;
res.set_content(createSuccessResponse(item), "application/json");
} else {
res.status = 500;
res.set_content(createErrorResponse("Failed to add item"),
"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());
}
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

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

@ -0,0 +1,32 @@
#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>
namespace nxl::autostore::webapi {
class StoreController
{
public:
StoreController(application::IItemRepository& itemRepository,
application::IClock& clock,
application::IOrderService& orderService);
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;
};
} // namespace nxl::autostore::webapi
Loading…
Cancel
Save