Mercurial > minori
diff src/core/filesystem.cc @ 382:0265e125f680
filesystem: implement filesystem watcher
I also ported the library code to use it as well. Once we implement
proper directory watching on Windows (and maybe others) this will
be fairly useful :)
| author | Paper <paper@tflc.us> |
|---|---|
| date | Thu, 06 Nov 2025 03:16:55 -0500 |
| parents | 5912dafc6e28 |
| children |
line wrap: on
line diff
--- a/src/core/filesystem.cc Thu Nov 06 01:17:24 2025 -0500 +++ b/src/core/filesystem.cc Thu Nov 06 03:16:55 2025 -0500 @@ -56,4 +56,118 @@ return GetDotPath() / "anime" / "posters"; } +/* ------------------------------------------------------------------------ */ +/* Ehhhhh */ + +class Watcher : public IWatcher { +public: + Watcher(void *opaque, const std::filesystem::path &path, EventHandler handler) + : path_(path) + , handler_(handler) + , opaque_(opaque) + { + } + + virtual ~Watcher() override + { + } + +protected: + std::filesystem::path path_; + EventHandler handler_; + void *opaque_; +}; + +/* ------------------------------------------------------------------------ */ +/* Non-recursive filesystem watcher. + * This is the portable version for non-Windows */ + +template<typename T> +class StdFilesystemWatcher : public Watcher { +public: + StdFilesystemWatcher(void *opaque, const std::filesystem::path &path, EventHandler handler) + : Watcher(opaque, path, handler) + { + } + + virtual ~StdFilesystemWatcher() override + { + } + + virtual void Process() override + { + /* Untoggle all paths. This allows us to only ever + * iterate over the directory ONCE. */ + UntoggleAllPaths(); + + for (const auto &item : T(path_)) { + std::filesystem::path p = item.path(); + + if (FindAndTogglePath(p)) + continue; + + /* Hand the path off to the listener */ + handler_(opaque_, p, Event::Created); + paths_.push_back({true, p}); + } + + DeleteUntoggledPaths(); + } + +protected: + bool FindAndTogglePath(const std::filesystem::path &p) { + for (auto &pp : paths_) { + if (pp.path == p) { + pp.found = true; + return true; + } + } + + return false; + } + + void UntoggleAllPaths() + { + for (auto &pp : paths_) + pp.found = false; + } + + void DeleteUntoggledPaths() + { + for (const auto &path : paths_) + if (!path.found) + handler_(opaque_, path.path, Event::Deleted); + + auto it = paths_.begin(); + + while (it != paths_.end()) { + if (!it->found) { + it = paths_.erase(it); + } else { + it++; + } + } + } + + struct PathStatus { + bool found; + std::filesystem::path path; + }; + + /* TODO this is probably DAMN slow */ + std::vector<PathStatus> paths_; +}; + +IWatcher *GetRecursiveFilesystemWatcher(void *opaque, + const std::filesystem::path &path, IWatcher::EventHandler handler) +{ + /* .... :) */ + return new StdFilesystemWatcher<std::filesystem::recursive_directory_iterator>(opaque, path, handler); +} + +IWatcher *GetFilesystemWatcher(void *opaque, const std::filesystem::path &path, IWatcher::EventHandler handler) +{ + return new StdFilesystemWatcher<std::filesystem::directory_iterator>(opaque, path, handler); +} + } // namespace Filesystem
