// D:\Dev\Mosis\MosisService\designer\src\hot_reload.cpp #include "hot_reload.h" #include #ifdef _WIN32 #include #endif namespace mosis { HotReload::HotReload(const std::filesystem::path& watch_path, ReloadCallback callback) : m_watch_path(watch_path) , m_callback(std::move(callback)) {} HotReload::~HotReload() { Stop(); } void HotReload::Start() { if (m_running) return; m_running = true; #ifdef _WIN32 // Create a manual-reset event for signaling shutdown m_stop_event = CreateEventW(nullptr, TRUE, FALSE, nullptr); if (!m_stop_event) { std::cerr << "Failed to create stop event" << std::endl; m_running = false; return; } m_notification_handle = FindFirstChangeNotificationW( m_watch_path.c_str(), TRUE, // Watch subtree FILE_NOTIFY_CHANGE_LAST_WRITE ); if (m_notification_handle == INVALID_HANDLE_VALUE) { std::cerr << "Failed to set up file watching" << std::endl; CloseHandle(m_stop_event); m_stop_event = nullptr; m_running = false; return; } #endif m_watch_thread = std::thread(&HotReload::WatchThread, this); } void HotReload::Stop() { m_running = false; #ifdef _WIN32 // Signal the stop event to wake up the watch thread if (m_stop_event) { SetEvent(m_stop_event); } #endif if (m_watch_thread.joinable()) { m_watch_thread.join(); } #ifdef _WIN32 if (m_notification_handle && m_notification_handle != INVALID_HANDLE_VALUE) { FindCloseChangeNotification(m_notification_handle); m_notification_handle = nullptr; } if (m_stop_event) { CloseHandle(m_stop_event); m_stop_event = nullptr; } #endif } void HotReload::WatchThread() { while (m_running) { #ifdef _WIN32 // Wait on both the file change notification and the stop event HANDLE handles[2] = { m_notification_handle, m_stop_event }; DWORD result = WaitForMultipleObjects(2, handles, FALSE, INFINITE); if (result == WAIT_OBJECT_0) { // File change notification // Debounce - wait a bit for file writes to complete std::this_thread::sleep_for(std::chrono::milliseconds(100)); if (m_callback && m_running) { m_callback(); } FindNextChangeNotification(m_notification_handle); } else if (result == WAIT_OBJECT_0 + 1) { // Stop event signaled - exit the loop break; } // WAIT_FAILED or other errors will just loop and check m_running #else // TODO: Linux inotify / macOS FSEvents implementation std::this_thread::sleep_for(std::chrono::milliseconds(100)); #endif } } } // namespace mosis