#include "NotificationModule.h" #include namespace aissia { NotificationModule::NotificationModule() { m_logger = spdlog::get("NotificationModule"); if (!m_logger) { m_logger = spdlog::stdout_color_mt("NotificationModule"); } m_config = std::make_unique("config"); } void NotificationModule::setConfiguration(const grove::IDataNode& configNode, grove::IIO* io, grove::ITaskScheduler* scheduler) { m_io = io; m_config = std::make_unique("config"); // Charger la configuration m_language = configNode.getString("language", "fr"); m_silentMode = configNode.getBool("silentMode", false); m_ttsEnabled = configNode.getBool("ttsEnabled", false); m_maxQueueSize = configNode.getInt("maxQueueSize", 50); m_logger->info("NotificationModule configuré: langue={}, silent={}, tts={}", m_language, m_silentMode, m_ttsEnabled); } const grove::IDataNode& NotificationModule::getConfiguration() { return *m_config; } void NotificationModule::process(const grove::IDataNode& input) { // Traiter la file de notifications processNotificationQueue(); } void NotificationModule::notify(const std::string& title, const std::string& message, Priority priority) { if (m_silentMode && priority != Priority::URGENT) { return; // Ignorer les notifications non-urgentes en mode silencieux } Notification notif; notif.id = std::to_string(++m_notificationCount); notif.title = title; notif.message = message; notif.priority = priority; notif.language = m_language; notif.read = false; notif.timestamp = 0; // Sera mis à jour lors du process // Limiter la taille de la queue while (static_cast(m_pendingNotifications.size()) >= m_maxQueueSize) { m_pendingNotifications.pop(); } m_pendingNotifications.push(notif); if (priority == Priority::URGENT) { m_urgentCount++; } } void NotificationModule::processNotificationQueue() { // Traiter jusqu'à 3 notifications par frame pour éviter le spam int processed = 0; while (!m_pendingNotifications.empty() && processed < 3) { Notification notif = m_pendingNotifications.front(); m_pendingNotifications.pop(); displayNotification(notif); processed++; } } void NotificationModule::displayNotification(const Notification& notif) { std::string emoji = priorityToEmoji(notif.priority); std::string priorityStr = priorityToString(notif.priority); // Affichage console (sera remplacé par Windows toast + TTS) switch (notif.priority) { case Priority::URGENT: m_logger->warn("{} [{}] {}: {}", emoji, priorityStr, notif.title, notif.message); break; case Priority::HIGH: m_logger->info("{} [{}] {}: {}", emoji, priorityStr, notif.title, notif.message); break; case Priority::NORMAL: m_logger->info("{} {}: {}", emoji, notif.title, notif.message); break; case Priority::LOW: m_logger->debug("{} {}: {}", emoji, notif.title, notif.message); break; } // TODO: Intégrer Windows Toast notifications // TODO: Intégrer TTS si m_ttsEnabled } std::string NotificationModule::priorityToString(Priority p) { switch (p) { case Priority::LOW: return "INFO"; case Priority::NORMAL: return "RAPPEL"; case Priority::HIGH: return "IMPORTANT"; case Priority::URGENT: return "URGENT"; default: return "?"; } } std::string NotificationModule::priorityToEmoji(Priority p) { switch (p) { case Priority::LOW: return "[i]"; case Priority::NORMAL: return "[*]"; case Priority::HIGH: return "[!]"; case Priority::URGENT: return "[!!!]"; default: return "[ ]"; } } std::unique_ptr NotificationModule::getHealthStatus() { auto status = std::make_unique("status"); status->setString("status", "running"); status->setInt("pendingCount", m_pendingNotifications.size()); status->setInt("totalNotifications", m_notificationCount); status->setInt("urgentCount", m_urgentCount); status->setBool("silentMode", m_silentMode); return status; } void NotificationModule::shutdown() { // Vider la queue avant arrêt while (!m_pendingNotifications.empty()) { displayNotification(m_pendingNotifications.front()); m_pendingNotifications.pop(); } m_logger->info("NotificationModule arrêté. Total: {} notifications ({} urgentes)", m_notificationCount, m_urgentCount); } std::unique_ptr NotificationModule::getState() { auto state = std::make_unique("state"); state->setInt("notificationCount", m_notificationCount); state->setInt("urgentCount", m_urgentCount); state->setInt("pendingCount", m_pendingNotifications.size()); m_logger->debug("État sauvegardé: {} notifications", m_notificationCount); return state; } void NotificationModule::setState(const grove::IDataNode& state) { m_notificationCount = state.getInt("notificationCount", 0); m_urgentCount = state.getInt("urgentCount", 0); // Note: On ne restaure pas la queue - les notifications en attente sont perdues au reload m_logger->info("État restauré: {} notifications historiques", m_notificationCount); } } // namespace aissia extern "C" { grove::IModule* createModule() { return new aissia::NotificationModule(); } void destroyModule(grove::IModule* module) { delete module; } }