aissia/src/services/PlatformService.cpp
StillHammer 26a5d3438b refactor: Services architecture for GroveEngine compliance
- Create 4 infrastructure services (LLM, Storage, Platform, Voice)
- Refactor all modules to pure business logic (no HTTP/SQLite/Win32)
- Add bundled SQLite amalgamation for MinGW compatibility
- Make OpenSSL optional in CMake configuration
- Fix topic naming convention (colon format)
- Add succession documentation

Build status: CMake config needs SQLite C language fix (documented)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-26 11:57:53 +08:00

140 lines
4.4 KiB
C++

#include "PlatformService.hpp"
#include <spdlog/sinks/stdout_color_sinks.h>
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<float>(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<int>(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<grove::JsonDataNode>("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<grove::JsonDataNode>("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<grove::JsonDataNode>("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<grove::JsonDataNode>("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