summaryrefslogtreecommitdiff
path: root/Userland
diff options
context:
space:
mode:
Diffstat (limited to 'Userland')
-rw-r--r--Userland/Libraries/LibConfig/CMakeLists.txt1
-rw-r--r--Userland/Libraries/LibConfig/Client.cpp27
-rw-r--r--Userland/Libraries/LibConfig/Client.h10
-rw-r--r--Userland/Libraries/LibConfig/Listener.cpp44
-rw-r--r--Userland/Libraries/LibConfig/Listener.h27
-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
9 files changed, 188 insertions, 15 deletions
diff --git a/Userland/Libraries/LibConfig/CMakeLists.txt b/Userland/Libraries/LibConfig/CMakeLists.txt
index 04527241bd..f4506dc610 100644
--- a/Userland/Libraries/LibConfig/CMakeLists.txt
+++ b/Userland/Libraries/LibConfig/CMakeLists.txt
@@ -1,5 +1,6 @@
set(SOURCES
Client.cpp
+ Listener.cpp
)
set(GENERATED_SOURCES
diff --git a/Userland/Libraries/LibConfig/Client.cpp b/Userland/Libraries/LibConfig/Client.cpp
index a3c3bef4b3..2a53ecee8f 100644
--- a/Userland/Libraries/LibConfig/Client.cpp
+++ b/Userland/Libraries/LibConfig/Client.cpp
@@ -5,6 +5,7 @@
*/
#include <LibConfig/Client.h>
+#include <LibConfig/Listener.h>
namespace Config {
@@ -24,6 +25,11 @@ void Client::pledge_domains(Vector<String> const& domains)
async_pledge_domains(domains);
}
+void Client::monitor_domain(String const& domain)
+{
+ async_monitor_domain(domain);
+}
+
String Client::read_string(StringView domain, StringView group, StringView key, StringView fallback)
{
return read_string_value(domain, group, key).value_or(fallback);
@@ -54,4 +60,25 @@ void Client::write_bool(StringView domain, StringView group, StringView key, boo
async_write_bool_value(domain, group, key, value);
}
+void Client::notify_changed_string_value(String const& domain, String const& group, String const& key, String const& value)
+{
+ Listener::for_each([&](auto& listener) {
+ listener.config_string_did_change(domain, group, key, value);
+ });
+}
+
+void Client::notify_changed_i32_value(String const& domain, String const& group, String const& key, i32 value)
+{
+ Listener::for_each([&](auto& listener) {
+ listener.config_i32_did_change(domain, group, key, value);
+ });
+}
+
+void Client::notify_changed_bool_value(String const& domain, String const& group, String const& key, bool value)
+{
+ Listener::for_each([&](auto& listener) {
+ listener.config_bool_did_change(domain, group, key, value);
+ });
+}
+
}
diff --git a/Userland/Libraries/LibConfig/Client.h b/Userland/Libraries/LibConfig/Client.h
index 395a3188fc..ce6efdbf3f 100644
--- a/Userland/Libraries/LibConfig/Client.h
+++ b/Userland/Libraries/LibConfig/Client.h
@@ -22,6 +22,7 @@ class Client final
public:
void pledge_domains(Vector<String> const&);
+ void monitor_domain(String const&);
String read_string(StringView domain, StringView group, StringView key, StringView fallback);
i32 read_i32(StringView domain, StringView group, StringView key, i32 fallback);
@@ -38,6 +39,10 @@ private:
: IPC::ServerConnection<ConfigClientEndpoint, ConfigServerEndpoint>(*this, "/tmp/portal/config")
{
}
+
+ void notify_changed_string_value(String const& domain, String const& group, String const& key, String const& value) override;
+ void notify_changed_i32_value(String const& domain, String const& group, String const& key, i32 value) override;
+ void notify_changed_bool_value(String const& domain, String const& group, String const& key, bool value) override;
};
inline String read_string(StringView domain, StringView group, StringView key, StringView fallback = {})
@@ -80,4 +85,9 @@ inline void pledge_domains(String const& domains)
Client::the().pledge_domains({ domains });
}
+inline void monitor_domain(String const& domain)
+{
+ Client::the().monitor_domain(domain);
+}
+
}
diff --git a/Userland/Libraries/LibConfig/Listener.cpp b/Userland/Libraries/LibConfig/Listener.cpp
new file mode 100644
index 0000000000..dbf452cded
--- /dev/null
+++ b/Userland/Libraries/LibConfig/Listener.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <AK/Function.h>
+#include <AK/HashTable.h>
+#include <AK/String.h>
+#include <LibConfig/Listener.h>
+
+namespace Config {
+
+static HashTable<Listener*> s_listeners;
+
+Listener::Listener()
+{
+ s_listeners.set(this);
+}
+
+Listener::~Listener()
+{
+ s_listeners.remove(this);
+}
+
+void Listener::for_each(Function<void(Listener&)> callback)
+{
+ for (auto* listener : s_listeners)
+ callback(*listener);
+}
+
+void Listener::config_string_did_change(String const&, String const&, String const&, String const&)
+{
+}
+
+void Listener::config_i32_did_change(String const&, String const&, String const&, i32)
+{
+}
+
+void Listener::config_bool_did_change(String const&, String const&, String const&, bool)
+{
+}
+
+}
diff --git a/Userland/Libraries/LibConfig/Listener.h b/Userland/Libraries/LibConfig/Listener.h
new file mode 100644
index 0000000000..239a7d1561
--- /dev/null
+++ b/Userland/Libraries/LibConfig/Listener.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/Forward.h>
+
+namespace Config {
+
+class Listener {
+public:
+ virtual ~Listener();
+
+ static void for_each(Function<void(Listener&)>);
+
+ virtual void config_string_did_change(String const& domain, String const& group, String const& key, String const& value);
+ virtual void config_i32_did_change(String const& domain, String const& group, String const& key, i32 value);
+ virtual void config_bool_did_change(String const& domain, String const& group, String const& key, bool value);
+
+protected:
+ Listener();
+};
+
+}
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)