summaryrefslogtreecommitdiff
path: root/Userland/Services
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2021-08-26 19:05:50 +0200
committerAndreas Kling <kling@serenityos.org>2021-08-26 23:41:38 +0200
commitedf784340999b6e8f44241e04e6d6f8afc27be29 (patch)
treee2008782c0bbc1e7bbfff08202e717febbb2ac13 /Userland/Services
parent9509f2ff87e10f87f4710749562e35be016a8a21 (diff)
downloadserenity-edf784340999b6e8f44241e04e6d6f8afc27be29.zip
ConfigServer+LibConfig: Add way for clients to listen for config changes
This patch adds a Config::Listener abstract class that anyone can inherit from and receive notifications when configuration values change. We don't yet monitor file system changes, so these only work for changes made by ConfigServer itself. In order to receive these notifications, clients must monitor the domain by calling monitor_domain(). Only pledged domains can be monitored. Note that the client initiating the change does not get notified.
Diffstat (limited to 'Userland/Services')
-rw-r--r--Userland/Services/ConfigServer/ClientConnection.cpp86
-rw-r--r--Userland/Services/ConfigServer/ClientConnection.h3
-rw-r--r--Userland/Services/ConfigServer/ConfigClient.ipc3
-rw-r--r--Userland/Services/ConfigServer/ConfigServer.ipc2
4 files changed, 79 insertions, 15 deletions
diff --git a/Userland/Services/ConfigServer/ClientConnection.cpp b/Userland/Services/ConfigServer/ClientConnection.cpp
index 3551a1af5b..246a95e10f 100644
--- a/Userland/Services/ConfigServer/ClientConnection.cpp
+++ b/Userland/Services/ConfigServer/ClientConnection.cpp
@@ -12,6 +12,25 @@ namespace ConfigServer {
static HashMap<int, RefPtr<ClientConnection>> s_connections;
+struct CachedDomain {
+ String domain;
+ NonnullRefPtr<Core::ConfigFile> config;
+};
+
+static HashMap<String, NonnullOwnPtr<CachedDomain>> s_cache;
+
+static Core::ConfigFile& ensure_domain_config(String const& domain)
+{
+ auto it = s_cache.find(domain);
+ if (it != s_cache.end())
+ return *it->value->config;
+
+ auto config = Core::ConfigFile::open_for_app(domain, Core::ConfigFile::AllowWriting::Yes);
+ auto cache_entry = make<CachedDomain>(domain, config);
+ s_cache.set(domain, move(cache_entry));
+ return *config;
+}
+
ClientConnection::ClientConnection(NonnullRefPtr<Core::LocalSocket> client_socket, int client_id)
: IPC::ClientConnection<ConfigClientEndpoint, ConfigServerEndpoint>(*this, move(client_socket), client_id)
{
@@ -38,6 +57,16 @@ void ClientConnection::pledge_domains(Vector<String> const& domains)
m_pledged_domains.set(domain);
}
+void ClientConnection::monitor_domain(String const& domain)
+{
+ if (m_has_pledged && !m_pledged_domains.contains(domain)) {
+ did_misbehave("Attempt to monitor non-pledged domain");
+ return;
+ }
+
+ m_monitored_domains.set(domain);
+}
+
bool ClientConnection::validate_access(String const& domain, String const& group, String const& key)
{
if (!m_has_pledged)
@@ -53,10 +82,10 @@ Messages::ConfigServer::ReadStringValueResponse ClientConnection::read_string_va
if (!validate_access(domain, group, key))
return nullptr;
- auto config = Core::ConfigFile::open_for_app(domain);
- if (!config->has_key(group, key))
+ auto& config = ensure_domain_config(domain);
+ if (!config.has_key(group, key))
return Optional<String> {};
- return Optional<String> { config->read_entry(group, key) };
+ return Optional<String> { config.read_entry(group, key) };
}
Messages::ConfigServer::ReadI32ValueResponse ClientConnection::read_i32_value(String const& domain, String const& group, String const& key)
@@ -64,10 +93,10 @@ Messages::ConfigServer::ReadI32ValueResponse ClientConnection::read_i32_value(St
if (!validate_access(domain, group, key))
return nullptr;
- auto config = Core::ConfigFile::open_for_app(domain);
- if (!config->has_key(group, key))
+ auto& config = ensure_domain_config(domain);
+ if (!config.has_key(group, key))
return Optional<i32> {};
- return Optional<i32> { config->read_num_entry(group, key) };
+ return Optional<i32> { config.read_num_entry(group, key) };
}
Messages::ConfigServer::ReadBoolValueResponse ClientConnection::read_bool_value(String const& domain, String const& group, String const& key)
@@ -75,10 +104,10 @@ Messages::ConfigServer::ReadBoolValueResponse ClientConnection::read_bool_value(
if (!validate_access(domain, group, key))
return nullptr;
- auto config = Core::ConfigFile::open_for_app(domain);
- if (!config->has_key(group, key))
+ auto& config = ensure_domain_config(domain);
+ if (!config.has_key(group, key))
return Optional<bool> {};
- return Optional<bool> { config->read_bool_entry(group, key) };
+ return Optional<bool> { config.read_bool_entry(group, key) };
}
void ClientConnection::write_string_value(String const& domain, String const& group, String const& key, String const& value)
@@ -86,8 +115,17 @@ void ClientConnection::write_string_value(String const& domain, String const& gr
if (!validate_access(domain, group, key))
return;
- auto config = Core::ConfigFile::open_for_app(domain, Core::ConfigFile::AllowWriting::Yes);
- config->write_entry(group, key, value);
+ auto& config = ensure_domain_config(domain);
+
+ if (config.has_key(group, key) && config.read_entry(group, key) == value)
+ return;
+
+ config.write_entry(group, key, value);
+
+ for (auto& it : s_connections) {
+ if (it.value != this && it.value->m_monitored_domains.contains(domain))
+ it.value->async_notify_changed_string_value(domain, group, key, value);
+ }
}
void ClientConnection::write_i32_value(String const& domain, String const& group, String const& key, i32 value)
@@ -95,8 +133,17 @@ void ClientConnection::write_i32_value(String const& domain, String const& group
if (!validate_access(domain, group, key))
return;
- auto config = Core::ConfigFile::open_for_app(domain, Core::ConfigFile::AllowWriting::Yes);
- config->write_num_entry(group, key, value);
+ auto& config = ensure_domain_config(domain);
+
+ if (config.has_key(group, key) && config.read_num_entry(group, key) == value)
+ return;
+
+ config.write_num_entry(group, key, value);
+
+ for (auto& it : s_connections) {
+ if (it.value != this && it.value->m_monitored_domains.contains(domain))
+ it.value->async_notify_changed_i32_value(domain, group, key, value);
+ }
}
void ClientConnection::write_bool_value(String const& domain, String const& group, String const& key, bool value)
@@ -104,8 +151,17 @@ void ClientConnection::write_bool_value(String const& domain, String const& grou
if (!validate_access(domain, group, key))
return;
- auto config = Core::ConfigFile::open_for_app(domain, Core::ConfigFile::AllowWriting::Yes);
- config->write_bool_entry(group, key, value);
+ auto& config = ensure_domain_config(domain);
+
+ if (config.has_key(group, key) && config.read_bool_entry(group, key) == value)
+ return;
+
+ config.write_bool_entry(group, key, value);
+
+ for (auto& it : s_connections) {
+ if (it.value != this && it.value->m_monitored_domains.contains(domain))
+ it.value->async_notify_changed_bool_value(domain, group, key, value);
+ }
}
}
diff --git a/Userland/Services/ConfigServer/ClientConnection.h b/Userland/Services/ConfigServer/ClientConnection.h
index cdbc53ab64..55bd3ebb9c 100644
--- a/Userland/Services/ConfigServer/ClientConnection.h
+++ b/Userland/Services/ConfigServer/ClientConnection.h
@@ -24,6 +24,7 @@ private:
explicit ClientConnection(NonnullRefPtr<Core::LocalSocket>, int client_id);
virtual void pledge_domains(Vector<String> const&) override;
+ virtual void monitor_domain(String const&) override;
virtual Messages::ConfigServer::ReadStringValueResponse read_string_value([[maybe_unused]] String const& domain, [[maybe_unused]] String const& group, [[maybe_unused]] String const& key) override;
virtual Messages::ConfigServer::ReadI32ValueResponse read_i32_value([[maybe_unused]] String const& domain, [[maybe_unused]] String const& group, [[maybe_unused]] String const& key) override;
virtual Messages::ConfigServer::ReadBoolValueResponse read_bool_value([[maybe_unused]] String const& domain, [[maybe_unused]] String const& group, [[maybe_unused]] String const& key) override;
@@ -35,6 +36,8 @@ private:
bool m_has_pledged { false };
HashTable<String> m_pledged_domains;
+
+ HashTable<String> m_monitored_domains;
};
}
diff --git a/Userland/Services/ConfigServer/ConfigClient.ipc b/Userland/Services/ConfigServer/ConfigClient.ipc
index bd0318b3ad..d8436b671d 100644
--- a/Userland/Services/ConfigServer/ConfigClient.ipc
+++ b/Userland/Services/ConfigServer/ConfigClient.ipc
@@ -1,3 +1,6 @@
endpoint ConfigClient
{
+ notify_changed_string_value(String domain, String group, String key, String value) =|
+ notify_changed_i32_value(String domain, String group, String key, i32 value) =|
+ notify_changed_bool_value(String domain, String group, String key, bool value) =|
}
diff --git a/Userland/Services/ConfigServer/ConfigServer.ipc b/Userland/Services/ConfigServer/ConfigServer.ipc
index 9ce1bbc70a..055e85241f 100644
--- a/Userland/Services/ConfigServer/ConfigServer.ipc
+++ b/Userland/Services/ConfigServer/ConfigServer.ipc
@@ -2,6 +2,8 @@ endpoint ConfigServer
{
pledge_domains(Vector<String> domains) =|
+ monitor_domain(String domain) =|
+
read_string_value(String domain, String group, String key) => (Optional<String> value)
read_i32_value(String domain, String group, String key) => (Optional<i32> value)
read_bool_value(String domain, String group, String key) => (Optional<bool> value)