// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include "StartupIndexer.hpp" #include #include #include #include "Constants.hpp" #include #include namespace service::detail { namespace fs = std::filesystem; namespace { using namespace std::string_literals; // File extensions indexing allow list static constexpr const char *allowed_exts[]{".wav", ".mp3", ".flac"}; // List of initial dirs for scan const std::vector start_dirs{purefs::dir::getUserDiskPath() / "music"}; // Lock file name const auto lock_file_name = purefs::dir::getUserDiskPath() / ".directory_is_indexed"; // Time for indexing first unit constexpr auto timer_indexing_delay = 400; // Time for initial delay after start constexpr auto timer_run_delay = 10000; } // namespace // Process single entry auto StartupIndexer::processEntry(std::shared_ptr svc, const std::filesystem::recursive_directory_iterator::value_type &entry) -> void { using namespace std::string_view_literals; if (fs::is_regular_file(entry)) { for (const auto &ext : allowed_exts) { if (fs::path(entry).extension() == ext) { const auto abspath = fs::absolute(entry).string(); const auto inotifyMsg = std::make_shared( purefs::fs::inotify_flags::close_write, abspath, ""sv); svc->bus.sendUnicast(inotifyMsg, std::string(service::name::file_indexer)); } } } } // On timer timeout auto StartupIndexer::onTimerTimeout(std::shared_ptr svc) -> void { if (!mStarted) { mIdxTimer.restart(std::chrono::milliseconds{timer_indexing_delay}); mStarted = true; } if (mSubDirIterator == std::filesystem::recursive_directory_iterator()) { if (mTopDirIterator == std::cend(start_dirs)) { createLockFile(); LOG_INFO("Initial startup indexer - Finished ..."); mIdxTimer.stop(); } else { mSubDirIterator = fs::recursive_directory_iterator(*mTopDirIterator); mTopDirIterator++; } } else { processEntry(svc, *mSubDirIterator); mSubDirIterator++; } } // Setup timers for notification auto StartupIndexer::setupTimers(std::shared_ptr svc, std::string_view svc_name) -> void { mIdxTimer = sys::TimerFactory::createPeriodicTimer(svc.get(), "file_indexing", std::chrono::milliseconds{timer_run_delay}, [this, svc](sys::Timer &) { onTimerTimeout(svc); }); mIdxTimer.start(); } // Start the initial file indexing auto StartupIndexer::start(std::shared_ptr svc, std::string_view svc_name) -> void { if (!hasLockFile()) { LOG_INFO("Initial startup indexer - Started..."); mTopDirIterator = std::begin(start_dirs); setupTimers(svc, svc_name); } else { LOG_INFO("Initial startup indexer - Not needed..."); } } // Create lock file auto StartupIndexer::createLockFile() -> bool { std::ofstream ofs(lock_file_name); ofs << time(nullptr); return ofs.good(); } // Check if lock file exists auto StartupIndexer::hasLockFile() -> bool { std::error_code ec; return fs::is_regular_file(lock_file_name, ec); } } // namespace service::detail