~aleteoryx/muditaos

ref: 65f30a0df267b73d985840af30e31b44c0235dcd muditaos/module-services/service-fileindexer/StartupIndexer.cpp -rw-r--r-- 4.5 KiB
65f30a0d — Pawel Olejniczak [CP-1448] Add storage info to device info endpoint 3 years 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
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

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

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

#include <filesystem>
#include <fstream>

namespace service::detail
{
    namespace fs = std::filesystem;
    namespace
    {
        using namespace std::string_literals;
        // 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

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

    // Process single entry
    auto StartupIndexer::processEntry(std::shared_ptr<sys::Service> svc,
                                      const std::filesystem::recursive_directory_iterator::value_type &entry) -> void
    {
        using namespace std::string_view_literals;
        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));
        }
    }

    // On timer timeout
    auto StartupIndexer::onTimerTimeout(std::shared_ptr<sys::Service> svc) -> void
    {
        if (mForceStop) {
            return;
        }
        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<sys::Service> 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<sys::Service> svc, std::string_view svc_name) -> void
    {
        if (!hasLockFile()) {
            LOG_INFO("Initial startup indexer - Started...");
            mTopDirIterator = std::begin(start_dirs);
            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();
    }

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

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

    auto StartupIndexer::removeLockFile() -> bool
    {
        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;
    }
} // namespace service::detail