#include "PlatformService.hpp" #include namespace aissia { PlatformService::PlatformService() { m_logger = spdlog::get("PlatformService"); if (!m_logger) { m_logger = spdlog::stdout_color_mt("PlatformService"); } } bool PlatformService::initialize(grove::IIO* io) { m_io = io; // Create platform-specific window tracker m_tracker = WindowTrackerFactory::create(); if (!m_tracker || !m_tracker->isAvailable()) { m_logger->warn("Window tracker not available on this platform"); return true; // Non-fatal, module can work without tracking } if (m_io) { grove::SubscriptionConfig config; m_io->subscribe("platform:query_window", config); } m_logger->info("PlatformService initialized: {}", m_tracker->getPlatformName()); return true; } void PlatformService::configure(int pollIntervalMs, int idleThresholdSeconds) { m_pollIntervalMs = pollIntervalMs; m_idleThresholdSeconds = idleThresholdSeconds; m_logger->debug("Configured: poll={}ms, idle={}s", pollIntervalMs, idleThresholdSeconds); } void PlatformService::process() { if (!m_tracker || !m_tracker->isAvailable()) return; // Use monotonic clock for timing static auto startTime = std::chrono::steady_clock::now(); auto now = std::chrono::steady_clock::now(); float currentTime = std::chrono::duration(now - startTime).count(); float pollIntervalSec = m_pollIntervalMs / 1000.0f; if (currentTime - m_lastPollTime >= pollIntervalSec) { m_lastPollTime = currentTime; pollWindowInfo(currentTime); } // Handle query requests if (m_io) { while (m_io->hasMessages() > 0) { auto msg = m_io->pullMessage(); if (msg.topic == "platform:query_window") { publishWindowInfo(); } } } } void PlatformService::pollWindowInfo(float currentTime) { std::string newApp = m_tracker->getCurrentAppName(); std::string newTitle = m_tracker->getCurrentWindowTitle(); // Check for app change if (newApp != m_currentApp) { int duration = static_cast(currentTime - m_appStartTime); if (!m_currentApp.empty() && duration > 0) { publishWindowChanged(m_currentApp, newApp, duration); } m_currentApp = newApp; m_currentWindowTitle = newTitle; m_appStartTime = currentTime; m_logger->debug("App: {} - {}", m_currentApp, m_currentWindowTitle.size() > 50 ? m_currentWindowTitle.substr(0, 50) + "..." : m_currentWindowTitle); } // Check idle state bool isIdle = m_tracker->isUserIdle(m_idleThresholdSeconds); if (isIdle && !m_wasIdle) { m_logger->info("User idle detected ({}s)", m_idleThresholdSeconds); if (m_io) { auto event = std::make_unique("idle"); event->setInt("idleSeconds", m_tracker->getIdleTimeSeconds()); m_io->publish("platform:idle_detected", std::move(event)); } } else if (!isIdle && m_wasIdle) { m_logger->info("User activity resumed"); if (m_io) { auto event = std::make_unique("active"); m_io->publish("platform:activity_resumed", std::move(event)); } } m_wasIdle = isIdle; // Publish periodic window info publishWindowInfo(); } void PlatformService::publishWindowInfo() { if (!m_io || !m_tracker) return; auto event = std::make_unique("window"); event->setString("appName", m_currentApp); event->setString("windowTitle", m_currentWindowTitle); event->setBool("isIdle", m_wasIdle); event->setInt("idleSeconds", m_tracker->getIdleTimeSeconds()); m_io->publish("platform:window_info", std::move(event)); } void PlatformService::publishWindowChanged(const std::string& oldApp, const std::string& newApp, int duration) { if (!m_io) return; auto event = std::make_unique("changed"); event->setString("oldApp", oldApp); event->setString("newApp", newApp); event->setInt("duration", duration); m_io->publish("platform:window_changed", std::move(event)); } void PlatformService::shutdown() { m_tracker.reset(); m_logger->info("PlatformService shutdown"); } } // namespace aissia