~aleteoryx/muditaos

ref: 2cd0e4721405c0bf263f311f27d38aadae6ac89f muditaos/module-services/service-fileindexer/StartupIndexer.cpp -rw-r--r-- 4.9 KiB
2cd0e472 — Lefucjusz [BH-000] Update Harmony 2.10.0 changelog 2 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md

#include "Common.hpp"
#include <service-fileindexer/StartupIndexer.hpp>
#include <service-fileindexer/ServiceFileIndexerName.hpp>

#include <Timers/TimerFactory.hpp>
#include <purefs/filesystem_paths.hpp>
#include <purefs/fs/inotify_message.hpp>
#include <log/log.hpp>

#include <fstream>
#include <queries/multimedia_files/QueryMultimediaFilesRemove.hpp>
#include <service-db/DBServiceAPI.hpp>

namespace service::detail
{
    namespace fs = std::filesystem;
    using namespace std::literals;
    using namespace std::chrono_literals;

    const auto lock_file_name        = purefs::dir::getSystemVarDirPath() / ".directory_is_indexed";
    constexpr auto indexing_interval = 50ms;
    constexpr auto start_delay       = 10000ms;

    bool isDirectoryFullyTraversed(const std::filesystem::recursive_directory_iterator &directory)
    {
        return directory == std::filesystem::recursive_directory_iterator();
    }

    bool createLockFile()
    {
        std::ofstream ofs(lock_file_name);
        ofs << time(nullptr);
        return ofs.good();
    }

    bool hasLockFile()
    {
        std::error_code ec;
        return fs::is_regular_file(lock_file_name, ec);
    }

    bool removeLockFile()
    {
        if (hasLockFile()) {
            std::error_code ec;
            if (!remove(lock_file_name, ec)) {
                LOG_ERROR("Failed to remove lock file, error: %d", ec.value());
                return false;
            }
        }
        return true;
    }

    std::optional<std::filesystem::recursive_directory_iterator> scanPath(std::vector<std::string>::const_iterator path)
    {
        std::error_code err;
        const auto mSubDirIterator = fs::recursive_directory_iterator(*path, err);
        if (err) {
            LOG_WARN("Directory '%s' not indexed, it does not exist", path->c_str());
            return std::nullopt;
        }
        return mSubDirIterator;
    }

    StartupIndexer::StartupIndexer(const std::vector<std::string> &paths) : directoriesToScan{paths}
    {}

    // Process single entry
    auto StartupIndexer::processEntry(std::shared_ptr<sys::Service> svc,
                                      const std::filesystem::recursive_directory_iterator::value_type &entry) -> void
    {
        if (fs::is_regular_file(entry)) {
            auto ext = fs::path(entry).extension();
            if (!isExtSupported(ext)) {
                LOG_WARN("Not supported ext - %s", ext.c_str());
                return;
            }

            const auto abspath = fs::absolute(entry).string();
            const auto inotifyMsg =
                std::make_shared<purefs::fs::message::inotify>(purefs::fs::inotify_flags::close_write, abspath, ""sv);
            svc->bus.sendUnicast(inotifyMsg, std::string(service::name::file_indexer));
        }
    }

    auto StartupIndexer::onTimerTimeout(std::shared_ptr<sys::Service> svc) -> void
    {
        if (mForceStop) {
            return;
        }
        if (isDirectoryFullyTraversed(mSubDirIterator)) {
            if (mTopDirIterator == std::cend(directoriesToScan)) {
                createLockFile();
                LOG_INFO("Initial startup indexer: Finished");
                mIdxTimer.stop();
                return;
            }
            else {
                if (auto result = scanPath(mTopDirIterator)) {
                    mSubDirIterator = *result;
                }
                mTopDirIterator++;
            }
        }
        else {
            processEntry(svc, *mSubDirIterator);
            mSubDirIterator++;
        }

        mIdxTimer.restart(indexing_interval);
    }

    // Setup timers for notification
    auto StartupIndexer::setupTimers(std::shared_ptr<sys::Service> svc, std::string_view svc_name) -> void
    {
        mIdxTimer = sys::TimerFactory::createSingleShotTimer(
            svc.get(), svc_name.data(), start_delay, [this, svc](auto &) { onTimerTimeout(svc); });
        mIdxTimer.start();
    }

    // Start the initial file indexing
    auto StartupIndexer::start(std::shared_ptr<sys::Service> svc, std::string_view svc_name) -> void
    {
        if (!hasLockFile()) {
            LOG_INFO("Initial startup indexer: Started");

            auto query = std::make_unique<db::multimedia_files::query::RemoveAll>();
            DBServiceAPI::GetQuery(svc.get(), db::Interface::Name::MultimediaFiles, std::move(query));

            mTopDirIterator = std::begin(directoriesToScan);
            setupTimers(svc, svc_name);
            mForceStop = false;
        }
        else {
            LOG_INFO("Initial startup indexer: Not needed");
        }
    }

    void StartupIndexer::stop()
    {
        mForceStop = true;
        mIdxTimer.stop();
    }

    void StartupIndexer::reset()
    {
        stop();
        removeLockFile();
    }
} // namespace service::detail