summaryrefslogtreecommitdiff
path: root/src/config/ConfigWatcher.cpp
diff options
context:
space:
mode:
authorvaxerski <vaxry@vaxry.net>2025-01-19 15:39:19 +0100
committervaxerski <vaxry@vaxry.net>2025-01-19 16:11:12 +0100
commit8dd2cd41fb4c5a5eb6886cc190419b36084cabfa (patch)
tree713dfeb4f2bf75c2a04ed93166b5f9109dac9a84 /src/config/ConfigWatcher.cpp
parent0a0e56d99c3b5f900ec561b3fe9a3c8a64fe1217 (diff)
core: move to inotify for monitoring the config files
instead of manually polling every second which is not efficient, use inotify. an added bonus is that inotify is much much faster
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,
+ });
+ }
+}