#include "StorageModule.h" #include #include namespace aissia { StorageModule::StorageModule() { m_logger = spdlog::get("StorageModule"); if (!m_logger) { m_logger = spdlog::stdout_color_mt("StorageModule"); } m_config = std::make_unique("config"); } void StorageModule::setConfiguration(const grove::IDataNode& configNode, grove::IIO* io, grove::ITaskScheduler* scheduler) { m_io = io; m_config = std::make_unique("config"); // Subscribe to topics if (m_io) { grove::SubscriptionConfig subConfig; m_io->subscribe("scheduler:task_completed", subConfig); m_io->subscribe("monitoring:app_changed", subConfig); m_io->subscribe("storage:session_saved", subConfig); m_io->subscribe("storage:error", subConfig); // Tool request handlers m_io->subscribe("storage:query", subConfig); m_io->subscribe("storage:command", subConfig); } m_logger->info("StorageModule configure (v2 - sans infrastructure)"); } const grove::IDataNode& StorageModule::getConfiguration() { return *m_config; } void StorageModule::process(const grove::IDataNode& input) { processMessages(); } void StorageModule::processMessages() { if (!m_io) return; while (m_io->hasMessages() > 0) { auto msg = m_io->pullMessage(); if (msg.topic == "scheduler:task_completed" && msg.data) { handleTaskCompleted(*msg.data); } else if (msg.topic == "monitoring:app_changed" && msg.data) { handleAppChanged(*msg.data); } else if (msg.topic == "storage:session_saved" && msg.data) { handleSessionSaved(*msg.data); } else if (msg.topic == "storage:error" && msg.data) { handleStorageError(*msg.data); } // Tool handlers else if (msg.topic == "storage:query" && msg.data) { handleToolQuery(*msg.data); } else if (msg.topic == "storage:command" && msg.data) { handleToolCommand(*msg.data); } } } void StorageModule::handleToolQuery(const grove::IDataNode& request) { std::string correlationId = request.getString("correlation_id", ""); std::string action = request.getString("action", ""); auto response = std::make_unique("response"); response->setString("correlation_id", correlationId); if (action == "query_notes") { std::string query = request.getString("query", ""); std::string tag = request.getString("tag", ""); int limit = request.getInt("limit", 10); // Search in-memory notes int count = 0; for (const auto& note : m_notes) { if (count >= limit) break; bool matches = query.empty() || note.content.find(query) != std::string::npos; if (!tag.empty()) { bool hasTag = false; for (const auto& t : note.tags) { if (t == tag) { hasTag = true; break; } } matches = matches && hasTag; } if (matches) { auto noteNode = std::make_unique("note_" + std::to_string(count)); noteNode->setString("id", note.id); noteNode->setString("content", note.content); noteNode->setString("timestamp", note.timestamp); response->setChild("note_" + std::to_string(count), std::move(noteNode)); count++; } } response->setInt("count", count); } else if (action == "get_session_history") { int days = request.getInt("days", 7); response->setInt("last_session_id", m_lastSessionId); response->setInt("total_saved", m_totalSaved); response->setString("note", "Full history requires StorageService query"); } else { response->setString("error", "unknown_action"); } m_io->publish("storage:response", std::move(response)); } void StorageModule::handleToolCommand(const grove::IDataNode& request) { std::string correlationId = request.getString("correlation_id", ""); std::string action = request.getString("action", ""); auto response = std::make_unique("response"); response->setString("correlation_id", correlationId); if (action == "save_note") { std::string content = request.getString("content", ""); if (content.empty()) { response->setString("error", "missing_content"); } else { // Create note in memory Note note; note.id = "note_" + std::to_string(m_notes.size()); note.content = content; note.timestamp = "now"; // TODO: proper timestamp m_notes.push_back(note); m_logger->info("Note saved: {}", note.id); // Also publish to StorageService for persistence if (m_io) { auto saveReq = std::make_unique("save_note"); saveReq->setString("content", content); m_io->publish("storage:save_note", std::move(saveReq)); } response->setBool("success", true); response->setString("note_id", note.id); } } else { response->setString("error", "unknown_action"); } m_io->publish("storage:response", std::move(response)); } void StorageModule::handleTaskCompleted(const grove::IDataNode& data) { std::string taskName = data.getString("taskName", "unknown"); int duration = data.getInt("duration", 0); bool hyperfocus = data.getBool("hyperfocus", false); m_logger->debug("Task completed: {} ({}min), publishing save request", taskName, duration); if (m_io) { auto request = std::make_unique("save"); request->setString("taskName", taskName); request->setInt("durationMinutes", duration); request->setBool("hyperfocus", hyperfocus); m_io->publish("storage:save_session", std::move(request)); m_pendingSaves++; } } void StorageModule::handleAppChanged(const grove::IDataNode& data) { std::string appName = data.getString("oldApp", ""); int duration = data.getInt("duration", 0); bool productive = data.getBool("wasProductive", false); if (appName.empty() || duration <= 0) return; m_logger->debug("App usage: {} ({}s), publishing save request", appName, duration); if (m_io) { auto request = std::make_unique("save"); request->setInt("sessionId", m_lastSessionId); request->setString("appName", appName); request->setInt("durationSeconds", duration); request->setBool("productive", productive); m_io->publish("storage:save_app_usage", std::move(request)); m_pendingSaves++; } } void StorageModule::handleSessionSaved(const grove::IDataNode& data) { m_lastSessionId = data.getInt("sessionId", 0); m_pendingSaves--; m_totalSaved++; m_logger->debug("Session saved: id={}", m_lastSessionId); } void StorageModule::handleStorageError(const grove::IDataNode& data) { std::string message = data.getString("message", "Unknown error"); m_pendingSaves--; m_logger->error("Storage error: {}", message); } std::unique_ptr StorageModule::getHealthStatus() { auto status = std::make_unique("status"); status->setString("status", "running"); status->setInt("lastSessionId", m_lastSessionId); status->setInt("pendingSaves", m_pendingSaves); status->setInt("totalSaved", m_totalSaved); return status; } void StorageModule::shutdown() { m_logger->info("StorageModule arrete. Total saved: {}", m_totalSaved); } std::unique_ptr StorageModule::getState() { auto state = std::make_unique("state"); state->setInt("lastSessionId", m_lastSessionId); state->setInt("totalSaved", m_totalSaved); return state; } void StorageModule::setState(const grove::IDataNode& state) { m_lastSessionId = state.getInt("lastSessionId", 0); m_totalSaved = state.getInt("totalSaved", 0); m_logger->info("Etat restore: lastSession={}, saved={}", m_lastSessionId, m_totalSaved); } } // namespace aissia extern "C" { grove::IModule* createModule() { return new aissia::StorageModule(); } void destroyModule(grove::IModule* module) { delete module; } }