1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 08:47:35 +00:00

ConfigServer: Monitor opened config files for changes

After opening a domain configuration and putting into our configuration
cache, we now monitor the underlying file for changes and send out
notifications to monitoring clients as needed.

This patch has three FIXME's:

- We create a new Core::FileWatcher for each domain.
- We don't yet detect removed keys.
- We don't know the type of key, so we assume everything is a string.

There are a number of ways we can solve those problems but let's not
hold up this patch while we wait for solutions. :^)
This commit is contained in:
Andreas Kling 2021-08-26 19:31:43 +02:00
parent 696dbc889f
commit 83d3720842
2 changed files with 28 additions and 1 deletions

View file

@ -7,6 +7,7 @@
#include "ClientConnection.h"
#include <ConfigServer/ConfigClientEndpoint.h>
#include <LibCore/ConfigFile.h>
#include <LibCore/FileWatcher.h>
namespace ConfigServer {
@ -15,6 +16,7 @@ static HashMap<int, RefPtr<ClientConnection>> s_connections;
struct CachedDomain {
String domain;
NonnullRefPtr<Core::ConfigFile> config;
RefPtr<Core::FileWatcher> watcher;
};
static HashMap<String, NonnullOwnPtr<CachedDomain>> s_cache;
@ -26,7 +28,30 @@ static Core::ConfigFile& ensure_domain_config(String const& domain)
return *it->value->config;
auto config = Core::ConfigFile::open_for_app(domain, Core::ConfigFile::AllowWriting::Yes);
auto cache_entry = make<CachedDomain>(domain, config);
// FIXME: Use a single FileWatcher with multiple watches inside.
auto watcher_or_error = Core::FileWatcher::create(InodeWatcherFlags::Nonblock);
VERIFY(!watcher_or_error.is_error());
auto result = watcher_or_error.value()->add_watch(config->filename(), Core::FileWatcherEvent::Type::ContentModified);
VERIFY(!result.is_error());
watcher_or_error.value()->on_change = [config, domain](auto&) {
auto new_config = Core::ConfigFile::open(config->filename());
// FIXME: Detect removed keys.
// FIXME: Detect type of keys.
for (auto& group : new_config->groups()) {
for (auto& key : new_config->keys(group)) {
auto old_value = config->read_entry(group, key);
auto new_value = new_config->read_entry(group, key);
if (old_value != new_value) {
for (auto& it : s_connections) {
if (it.value->is_monitoring_domain(domain)) {
it.value->async_notify_changed_string_value(domain, group, key, new_value);
}
}
}
}
}
};
auto cache_entry = make<CachedDomain>(domain, config, watcher_or_error.release_value());
s_cache.set(domain, move(cache_entry));
return *config;
}