summaryrefslogtreecommitdiff
path: root/src/config/ConfigWatcher.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/config/ConfigWatcher.cpp')
-rw-r--r--src/config/ConfigWatcher.cpp72
1 files changed, 72 insertions, 0 deletions
diff --git a/src/config/ConfigWatcher.cpp b/src/config/ConfigWatcher.cpp
new file mode 100644
index 00000000..38191e9e
--- /dev/null
+++ b/src/config/ConfigWatcher.cpp
@@ -0,0 +1,72 @@
+#include "ConfigWatcher.hpp"
+#include <sys/inotify.h>
+#include "../debug/Log.hpp"
+#include <ranges>
+#include <fcntl.h>
+
+CConfigWatcher::CConfigWatcher() : m_inotifyFd(inotify_init()) {
+ if (m_inotifyFd < 0) {
+ Debug::log(ERR, "CConfigWatcher couldn't open an inotify node. Config will not be automatically reloaded");
+ return;
+ }
+
+ const int FLAGS = fcntl(m_inotifyFd, F_GETFL, 0);
+ if (fcntl(m_inotifyFd, F_SETFL, FLAGS | O_NONBLOCK) < 0) {
+ Debug::log(ERR, "CConfigWatcher couldn't non-block inotify node. Config will not be automatically reloaded");
+ close(m_inotifyFd);
+ m_inotifyFd = -1;
+ return;
+ }
+}
+
+CConfigWatcher::~CConfigWatcher() {
+ if (m_inotifyFd >= 0)
+ close(m_inotifyFd);
+}
+
+int CConfigWatcher::getInotifyFD() {
+ return m_inotifyFd;
+}
+
+void CConfigWatcher::setWatchList(const std::vector<std::string>& paths) {
+
+ // we clear all watches first, because whichever fired is now invalid
+ // or that is at least what it seems to be.
+ // since we don't know which fired,
+ // plus it doesn't matter that much, these ops are done rarely and fast anyways.
+
+ // cleanup old paths
+ for (auto& watch : m_watches) {
+ inotify_rm_watch(m_inotifyFd, watch.wd);
+ }
+
+ m_watches.clear();
+
+ // add new paths
+ for (const auto& path : paths) {
+ m_watches.emplace_back(SInotifyWatch{
+ .wd = inotify_add_watch(m_inotifyFd, path.c_str(), IN_MODIFY),
+ .file = path,
+ });
+ }
+}
+
+void CConfigWatcher::setOnChange(const std::function<void(const SConfigWatchEvent&)>& fn) {
+ m_watchCallback = fn;
+}
+
+void CConfigWatcher::onInotifyEvent() {
+ inotify_event ev;
+ while (read(m_inotifyFd, &ev, sizeof(ev)) > 0) {
+ const auto WD = std::ranges::find_if(m_watches.begin(), m_watches.end(), [wd = ev.wd](const auto& e) { return e.wd == wd; });
+
+ if (WD == m_watches.end()) {
+ Debug::log(ERR, "CConfigWatcher: got an event for wd {} which we don't have?!", ev.wd);
+ return;
+ }
+
+ m_watchCallback(SConfigWatchEvent{
+ .file = WD->file,
+ });
+ }
+}