1#include "FileSystemWatcher.h"
6#include <sys/inotify.h>
13#include <unordered_map>
15using namespace std::chrono;
19 Item(
const FileSystemWatcher::CallbackFn& callback,
int descriptor,
const std::string& filename) : descriptor(descriptor) {
20 callbacks.push_back(callback);
21 fileTime = IO::getFileTime(filename);
24 FileSystemWatcher::CallbackList callbacks;
25 fs::file_time_type fileTime;
30 typedef std::unordered_map<std::string, Item> ItemMap;
32 int notifyHandle = -1;
35 std::thread watcherThread;
36 bool volatile watcherDone =
false;
38 ItemMap::const_iterator FindItem(
int wd)
const {
41 for (
auto i = items.begin(); i != e; ++i) {
42 if (i->second.descriptor == wd) {
51Cogs::FileSystemWatcher::FileSystemWatcher() {
52 storage =
new Storage();
53 storage->notifyHandle = inotify_init1(IN_NONBLOCK);
55 if (storage->notifyHandle == -1) {
60 storage->watcherThread = std::thread([
this]{
61 uint8_t buffer[
sizeof(inotify_event)];
62 inotify_event* e =
reinterpret_cast<inotify_event*
>(buffer);
65 while (!storage->watcherDone) {
66 int justread = read(storage->notifyHandle, buffer + bytesread,
sizeof(inotify_event) - bytesread);
71 std::this_thread::sleep_for(500ms);
81 bytesread += justread;
83 if (bytesread ==
sizeof(inotify_event)) {
86 std::lock_guard<std::mutex> lock(storage->mutex);
87 auto i = storage->FindItem(e->wd);
89 if (i != storage->items.end()) {
90 Event e = { i->first, EventType::FileUpdated };
92 for (
auto& callback : i->second.callbacks) {
101 std::lock_guard<std::mutex> lock(storage->mutex);
102 auto i = storage->FindItem(e->wd);
104 if (i != storage->items.end()) {
105 Event e = { i->first, EventType::FileDeleted };
107 for (
auto& callback : i->second.callbacks) {
110 inotify_rm_watch(storage->notifyHandle, i->second.descriptor);
111 storage->items.erase(i);
123Cogs::FileSystemWatcher::~FileSystemWatcher() {
124 if (storage->watcherThread.joinable()) {
125 storage->watcherDone =
true;
126 storage->watcherThread.join();
128 close(storage->notifyHandle);
132bool Cogs::FileSystemWatcher::watchFile(
const StringView& path,
const CallbackFn& callback) {
133 const auto absoluteFilePath = IO::absolute(path.to_string());
135 if (IO::exists(absoluteFilePath)) {
136 std::lock_guard<std::mutex> lock(storage->mutex);
137 auto i = storage->items.find(absoluteFilePath);
139 if (i == storage->items.end()) {
140 int descriptor = inotify_add_watch(storage->notifyHandle, absoluteFilePath.c_str(), IN_MODIFY | IN_MOVE_SELF | IN_DELETE_SELF);
142 if (descriptor >= 0) {
143 storage->items.emplace(absoluteFilePath, Item(callback, descriptor, absoluteFilePath));
148 i->second.callbacks.push_back(callback);
155bool Cogs::FileSystemWatcher::unwatchFile(
const StringView& path) {
156 const auto absoluteFilePath = IO::absolute(path.to_string());
157 std::lock_guard<std::mutex> lock(storage->mutex);
158 auto i = storage->items.find(absoluteFilePath);
160 if (i != storage->items.end()) {
161 inotify_rm_watch(storage->notifyHandle, i->second.descriptor);
162 storage->items.erase(i);
Contains all Cogs related functionality.