Optimizing project management and its requirements

This commit is contained in:
Sylvain Schneider
2026-03-12 18:56:19 +01:00
parent f25c5789ea
commit e64921702b
13 changed files with 354 additions and 190 deletions

View File

@@ -28,15 +28,15 @@ void CoreManager::init()
m_bus = make_unique<dBus::Bus>();
// Initialize other subsystems (e.g., logger, etc.)
m_logger = make_unique<logger::Logger>(*m_bus);
m_requirementManager = make_unique<requirementManager::RequirementManager>(*m_bus);
m_logger = make_unique<logger::Logger>(*m_bus);
m_projectManager = make_unique<project::ProjectManager>(*m_bus);
}
//--------------------------------------------------------------
/* Release resources used by the core manager (e.g., clean up the bus, etc.) */
void CoreManager::release()
{
// Clean up other subsystems (e.g., logger, etc.)
m_requirementManager.reset();
m_projectManager.reset();
m_logger.reset();
// Clean up the application bus

View File

@@ -1,7 +1,7 @@
#pragma once
#include "logger/logger.h"
#include "requirementManager/requirementManager.h"
#include "projectManager/projectManager.h"
#include <dBus/dBus.h>
#include <memory>
@@ -24,8 +24,8 @@ class CoreManager
protected:
std::unique_ptr<dBus::Bus> m_bus; // Application data bus
std::unique_ptr<logger::Logger> m_logger; // Application logger system
std::unique_ptr<requirementManager::RequirementManager> m_requirementManager; // Requirement manager system
std::unique_ptr<logger::Logger> m_logger; // Application logger system
std::unique_ptr<project::ProjectManager> m_projectManager; // Requirement manager system
private:
void init(); // Initialize the core manager (e.g., set up the bus, etc.)

View File

@@ -11,7 +11,7 @@ namespace core::logger
//--------------------------------------------------------------
class Logger : public dBus::Node
{
static constexpr auto LOG_PRINT_INTERVAL = std::chrono::seconds{ 1 };
static constexpr auto LOG_PRINT_INTERVAL = std::chrono::milliseconds{ 500 };
public:
Logger() = delete; // Default constructor

View File

@@ -0,0 +1,11 @@
#include "projectData.h"
using namespace std;
using namespace core::project;
//--------------------------------------------------------------
/* Get the root requirement */
ProjectData::RequirementPtr ProjectData::getRootRequirement()
{
return m_rootRequirement;
}
//--------------------------------------------------------------

View File

@@ -0,0 +1,29 @@
#pragma once
#include <api/requirement.h>
#include <memory>
namespace core::project
{
//--------------------------------------------------------------
class ProjectData
{
using RequirementPtr = std::shared_ptr<api::requirement::Requirement>;
public:
ProjectData() = default; // Default constructor
virtual ~ProjectData() = default; // Default destructor
ProjectData(const ProjectData &obj) = delete; // Copy constructor
ProjectData(ProjectData &&obj) noexcept = delete; // Move constructor
ProjectData &operator=(const ProjectData &obj) = delete; // Copy assignment operator
ProjectData &operator=(ProjectData &&obj) noexcept = delete; // Move assignment operator
RequirementPtr getRootRequirement(); // Get the root requirement
protected:
RequirementPtr m_rootRequirement; // Root requirement of the current project
private:
};
//--------------------------------------------------------------
} // namespace core::project

View File

@@ -0,0 +1,171 @@
#include "projectManager.h"
#include "projectData.h"
using namespace std;
using namespace core::project;
//--------------------------------------------------------------
/* Constructor */
ProjectManager::ProjectManager(dBus::Bus &bus)
: Node(bus)
{
// Initialize the bus listener thread
runBusListener();
}
//--------------------------------------------------------------
/* Default destructor */
ProjectManager::~ProjectManager()
{
// Stop the bus listener thread if it's running
stopBusListener();
}
//--------------------------------------------------------------
/* Open a project file and load the requirements */
void ProjectManager::openFile(const std::filesystem::path &filePath)
{
}
//--------------------------------------------------------------
/* Save the current requirements to a project file */
void ProjectManager::saveFile(const std::filesystem::path &filePath)
{
}
//--------------------------------------------------------------
/* Run the bus listener thread */
void ProjectManager::runBusListener()
{
// Subscribe to the bus for messages related to log entries
subscribe(dBus::makeID("project.file.operation"));
/* Start the bus listener thread to process incoming messages related to requirements.
* The thread will continuously wait for messages and process them until a stop is requested. */
// clang-format off
m_busListenerThread = std::jthread([this](const std::stop_token &stopToken)
{
while (!stopToken.stop_requested())
{
// Wait for a message to be received
syncWaitForMessage();
// Process all received messages
while (getMessageCount() > 0)
{
auto message = popNextMessage();
if (message)
processMessageBus(message);
}
}
});
// clang-format on
}
//--------------------------------------------------------------
/* Stop the bus listener thread */
void ProjectManager::stopBusListener()
{
// Stop event thread loop
m_busListenerThread.request_stop();
// Wake up event thread if waiting
notifyMessageQueue();
/* No need to join the thread explicitly as std::jthread will
* automatically join in its destructor.
* Subscribe to the bus will be automatically cleaned up in the
* Node destructor. */
}
//--------------------------------------------------------------
/* Process a message received from the bus */
void ProjectManager::processMessageBus(const Message_ptr &message)
{
const auto messageType = message->getMessageTypeID();
switch (messageType)
{
case dBus::makeID("project.file.operation"):
{
// Process project operation request
on_projectOperationEvent(message->as<dBus::RequestMessage<api::project::ProjectOperationEvent, void>>());
break;
}
}
}
//--------------------------------------------------------------
/* Process a file operation event */
void ProjectManager::on_projectOperationEvent(const ProjectOperationMessage_ptr &message)
{
// Sanity check
if (!message)
return;
switch (message->value.operationType)
{
using enum api::project::OperationType;
case Create:
on_projectCreateFileEvent(message);
break;
case Open:
on_projectOpenFileEvent(message);
break;
case Save:
case SaveAs:
on_projectSaveFileEvent(message);
break;
case Close:
on_projectCloseFileEvent(message);
break;
}
}
//--------------------------------------------------------------
/* Process a file creation event */
void ProjectManager::on_projectCreateFileEvent(const ProjectOperationMessage_ptr &message)
{
m_projectData = make_shared<ProjectData>();
message->responsePromise.set_value();
}
//--------------------------------------------------------------
/* Process a file open event */
void ProjectManager::on_projectOpenFileEvent(const ProjectOperationMessage_ptr &message)
{
// message->responsePromise.set_exception(std::make_exception_ptr(std::runtime_error("Open operation not implemented")));
try
{
openFile(message->value.filePath);
}
catch (const std::exception &e)
{
message->responsePromise.set_exception(std::make_exception_ptr(e));
}
message->responsePromise.set_value();
}
//--------------------------------------------------------------
/* Process a file save event */
void ProjectManager::on_projectSaveFileEvent(const ProjectOperationMessage_ptr &message)
{
try
{
if (message->value.operationType == api::project::OperationType::SaveAs)
{
if (message->value.filePath.empty())
throw std::runtime_error("File path is empty for SaveAs operation");
saveFile(message->value.filePath);
}
else if (message->value.operationType == api::project::OperationType::Save)
{
if (m_filePath.empty())
throw std::runtime_error("File path is empty for Save operation");
saveFile();
}
}
catch (const std::exception &e)
{
message->responsePromise.set_exception(std::make_exception_ptr(e));
}
message->responsePromise.set_value();
}
//--------------------------------------------------------------
/* Process a file close event */
void ProjectManager::on_projectCloseFileEvent(const ProjectOperationMessage_ptr &message)
{
m_projectData = {};
message->responsePromise.set_value();
}
//--------------------------------------------------------------

View File

@@ -0,0 +1,52 @@
#pragma once
#include <api/project.h>
#include <api/requirement.h>
#include <dBus/dBus.h>
#include <memory>
#include <thread>
namespace core::project
{
class ProjectData;
//--------------------------------------------------------------
class ProjectManager : public dBus::Node
{
using ProjectPtr = std::shared_ptr<ProjectData>;
public:
ProjectManager() = delete; // Default constructor
virtual ~ProjectManager(); // Default destructor
ProjectManager(const ProjectManager &obj) = delete; // Copy constructor
ProjectManager(ProjectManager &&obj) noexcept = delete; // Move constructor
ProjectManager &operator=(const ProjectManager &obj) = delete; // Copy assignment operator
ProjectManager &operator=(ProjectManager &&obj) noexcept = delete; // Move assignment operator
explicit ProjectManager(dBus::Bus &bus); // Constructor
protected:
std::filesystem::path m_filePath; // Path of the currently opened project file
ProjectPtr m_projectData; // Current project data, including the root requirement and all its sub-requirements
private:
void openFile(const std::filesystem::path &filePath); // Open a project file and load the requirements
void saveFile(const std::filesystem::path &filePath = ""); // Save the current requirements to a project file
// dBus management
using Message_ptr = std::shared_ptr<dBus::Message>;
void runBusListener(); // Run the bus listener thread
void stopBusListener(); // Stop the bus listener thread
void processMessageBus(const Message_ptr &message); // Process a message received from the bus
std::jthread m_busListenerThread; // Thread for listening to bus messages related to requirements
// Events processing
using ProjectOperationMessage_ptr = std::shared_ptr<dBus::RequestMessage<api::project::ProjectOperationEvent, void>>;
void on_projectOperationEvent(const ProjectOperationMessage_ptr &message); // Process a file operation event
void on_projectCreateFileEvent(const ProjectOperationMessage_ptr &message); // Process a file creation event
void on_projectOpenFileEvent(const ProjectOperationMessage_ptr &message); // Process a file opening event
void on_projectSaveFileEvent(const ProjectOperationMessage_ptr &message); // Process a file saving event
void on_projectCloseFileEvent(const ProjectOperationMessage_ptr &message); // Process a file closing event
};
//--------------------------------------------------------------
} // namespace core::project

View File

@@ -1,89 +0,0 @@
#include "requirementManager.h"
using namespace std;
using namespace core::requirementManager;
//--------------------------------------------------------------
/* Constructor */
RequirementManager::RequirementManager(dBus::Bus &bus)
: Node(bus)
{
// Initialize the bus listener thread
runBusListener();
}
//--------------------------------------------------------------
/* Default destructor */
RequirementManager::~RequirementManager()
{
// Stop the bus listener thread if it's running
stopBusListener();
}
//--------------------------------------------------------------
/* Get the root requirement */
api::requirement::Requirement &RequirementManager::getRootRequirement()
{
return m_rootRequirement;
}
//--------------------------------------------------------------
/* Run the bus listener thread */
void RequirementManager::runBusListener()
{
// Subscribe to the bus for messages related to log entries
subscribe(dBus::makeID("requirement.file.operation"));
/* Start the bus listener thread to process incoming messages related to requirements.
* The thread will continuously wait for messages and process them until a stop is requested. */
// clang-format off
m_busListenerThread = std::jthread([this](const std::stop_token &stopToken)
{
while (!stopToken.stop_requested())
{
// Wait for a message to be received
syncWaitForMessage();
// Process all received messages
while (getMessageCount() > 0)
{
auto message = popNextMessage();
if (message)
processMessageBus(message);
}
}
});
// clang-format on
}
//--------------------------------------------------------------
/* Stop the bus listener thread */
void RequirementManager::stopBusListener()
{
// Stop event thread loop
m_busListenerThread.request_stop();
// Wake up event thread if waiting
notifyMessageQueue();
/* No need to join the thread explicitly as std::jthread will
* automatically join in its destructor.
* Subscribe to the bus will be automatically cleaned up in the
* Node destructor. */
}
//--------------------------------------------------------------
/* Process a message received from the bus */
void RequirementManager::processMessageBus(const Message_ptr &message)
{
const auto messageType = message->getMessageTypeID();
switch (messageType)
{
case dBus::makeID("requirement.file.operation"):
{
// Process file operation request
const auto requestMessage = message->as<dBus::RequestMessage<api::requirement::FileOperationEvent, void>>();
if (!requestMessage)
break;
requestMessage->responsePromise.set_exception(std::make_exception_ptr(std::runtime_error("Failed to process file operation request")));
break;
}
}
}
//--------------------------------------------------------------

View File

@@ -1,38 +0,0 @@
#pragma once
#include <api/requirement.h>
#include <dBus/dBus.h>
#include <thread>
namespace core::requirementManager
{
//--------------------------------------------------------------
class RequirementManager : public dBus::Node
{
public:
RequirementManager() = delete; // Default constructor
virtual ~RequirementManager(); // Default destructor
RequirementManager(const RequirementManager &obj) = delete; // Copy constructor
RequirementManager(RequirementManager &&obj) noexcept = delete; // Move constructor
RequirementManager &operator=(const RequirementManager &obj) = delete; // Copy assignment operator
RequirementManager &operator=(RequirementManager &&obj) noexcept = delete; // Move assignment operator
explicit RequirementManager(dBus::Bus &bus); // Constructor
protected:
// dBus::Bus &m_bus; // Reference to the application bus
api::requirement::Requirement m_rootRequirement;
private:
api::requirement::Requirement &getRootRequirement(); // Get the root requirement
// dBus management
using Message_ptr = std::shared_ptr<dBus::Message>;
void runBusListener(); // Run the bus listener thread
void stopBusListener(); // Stop the bus listener thread
void processMessageBus(const Message_ptr &message); // Process a message received from the bus
std::jthread m_busListenerThread; // Thread for listening to bus messages related to requirements
};
//--------------------------------------------------------------
} // namespace core::requirementManager