mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 06:47:35 +00:00
Userland: Introduce ConfigServer and LibConfig
ConfigServer is an IPC service that provides access to application configuration and settings. The idea is to replace all uses of Core::ConfigFile with IPC requests to ConfigServer. This first cut of the API is pretty similar to Core::ConfigFile. The old: auto config = Core::ConfigFile::open_for_app("App"); auto value = config->read_entry("Group", "Key"); The new: auto value = Config::read_string("App", "Group", "Key"); ConfigServer uses the ~/.config directory as its backing store and all the files remain human-editable. :^)
This commit is contained in:
parent
c97f7ea23b
commit
bdcd0abf9d
12 changed files with 319 additions and 0 deletions
|
@ -1,3 +1,8 @@
|
||||||
|
[ConfigServer]
|
||||||
|
Socket=/tmp/portal/config
|
||||||
|
SocketPermissions=600
|
||||||
|
User=anon
|
||||||
|
|
||||||
[RequestServer]
|
[RequestServer]
|
||||||
Socket=/tmp/portal/request
|
Socket=/tmp/portal/request
|
||||||
SocketPermissions=600
|
SocketPermissions=600
|
||||||
|
|
|
@ -4,6 +4,7 @@ add_subdirectory(LibC)
|
||||||
add_subdirectory(LibCards)
|
add_subdirectory(LibCards)
|
||||||
add_subdirectory(LibChess)
|
add_subdirectory(LibChess)
|
||||||
add_subdirectory(LibCompress)
|
add_subdirectory(LibCompress)
|
||||||
|
add_subdirectory(LibConfig)
|
||||||
add_subdirectory(LibCore)
|
add_subdirectory(LibCore)
|
||||||
add_subdirectory(LibCoredump)
|
add_subdirectory(LibCoredump)
|
||||||
add_subdirectory(LibCpp)
|
add_subdirectory(LibCpp)
|
||||||
|
|
11
Userland/Libraries/LibConfig/CMakeLists.txt
Normal file
11
Userland/Libraries/LibConfig/CMakeLists.txt
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
set(SOURCES
|
||||||
|
Client.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(GENERATED_SOURCES
|
||||||
|
../../Services/ConfigServer/ConfigServerEndpoint.h
|
||||||
|
../../Services/ConfigServer/ConfigClientEndpoint.h
|
||||||
|
)
|
||||||
|
|
||||||
|
serenity_lib(LibConfig config)
|
||||||
|
target_link_libraries(LibConfig LibIPC)
|
50
Userland/Libraries/LibConfig/Client.cpp
Normal file
50
Userland/Libraries/LibConfig/Client.cpp
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <LibConfig/Client.h>
|
||||||
|
|
||||||
|
namespace Config {
|
||||||
|
|
||||||
|
static RefPtr<Client> s_the = nullptr;
|
||||||
|
|
||||||
|
Client& Client::the()
|
||||||
|
{
|
||||||
|
if (!s_the || !s_the->is_open())
|
||||||
|
s_the = Client::construct();
|
||||||
|
return *s_the;
|
||||||
|
}
|
||||||
|
|
||||||
|
String Client::read_string(StringView domain, StringView group, StringView key, StringView fallback)
|
||||||
|
{
|
||||||
|
return read_string_value(domain, group, key).value_or(fallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
i32 Client::read_i32(StringView domain, StringView group, StringView key, i32 fallback)
|
||||||
|
{
|
||||||
|
return read_i32_value(domain, group, key).value_or(fallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Client::read_bool(StringView domain, StringView group, StringView key, bool fallback)
|
||||||
|
{
|
||||||
|
return read_bool_value(domain, group, key).value_or(fallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::write_string(StringView domain, StringView group, StringView key, StringView value)
|
||||||
|
{
|
||||||
|
async_write_string_value(domain, group, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::write_i32(StringView domain, StringView group, StringView key, i32 value)
|
||||||
|
{
|
||||||
|
async_write_i32_value(domain, group, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::write_bool(StringView domain, StringView group, StringView key, bool value)
|
||||||
|
{
|
||||||
|
async_write_bool_value(domain, group, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
71
Userland/Libraries/LibConfig/Client.h
Normal file
71
Userland/Libraries/LibConfig/Client.h
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ConfigServer/ConfigClientEndpoint.h>
|
||||||
|
#include <ConfigServer/ConfigServerEndpoint.h>
|
||||||
|
#include <LibCore/File.h>
|
||||||
|
#include <LibCore/Promise.h>
|
||||||
|
#include <LibCore/StandardPaths.h>
|
||||||
|
#include <LibIPC/ServerConnection.h>
|
||||||
|
|
||||||
|
namespace Config {
|
||||||
|
|
||||||
|
class Client final
|
||||||
|
: public IPC::ServerConnection<ConfigClientEndpoint, ConfigServerEndpoint>
|
||||||
|
, public ConfigClientEndpoint {
|
||||||
|
C_OBJECT(Client);
|
||||||
|
|
||||||
|
public:
|
||||||
|
String read_string(StringView domain, StringView group, StringView key, StringView fallback);
|
||||||
|
i32 read_i32(StringView domain, StringView group, StringView key, i32 fallback);
|
||||||
|
bool read_bool(StringView domain, StringView group, StringView key, bool fallback);
|
||||||
|
|
||||||
|
void write_string(StringView domain, StringView group, StringView key, StringView value);
|
||||||
|
void write_i32(StringView domain, StringView group, StringView key, i32 value);
|
||||||
|
void write_bool(StringView domain, StringView group, StringView key, bool value);
|
||||||
|
|
||||||
|
static Client& the();
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit Client()
|
||||||
|
: IPC::ServerConnection<ConfigClientEndpoint, ConfigServerEndpoint>(*this, "/tmp/portal/config")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline String read_string(StringView domain, StringView group, StringView key, StringView fallback = {})
|
||||||
|
{
|
||||||
|
return Client::the().read_string(domain, group, key, fallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline i32 read_i32(StringView domain, StringView group, StringView key, i32 fallback = 0)
|
||||||
|
{
|
||||||
|
return Client::the().read_i32(domain, group, key, fallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool read_bool(StringView domain, StringView group, StringView key, bool fallback = false)
|
||||||
|
{
|
||||||
|
return Client::the().read_bool(domain, group, key, fallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void write_string(StringView domain, StringView group, StringView key, StringView value)
|
||||||
|
{
|
||||||
|
Client::the().write_string(domain, group, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void write_i32(StringView domain, StringView group, StringView key, i32 value)
|
||||||
|
{
|
||||||
|
Client::the().write_i32(domain, group, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void write_bool(StringView domain, StringView group, StringView key, bool value)
|
||||||
|
{
|
||||||
|
Client::the().write_bool(domain, group, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
add_subdirectory(AudioServer)
|
add_subdirectory(AudioServer)
|
||||||
add_subdirectory(ChessEngine)
|
add_subdirectory(ChessEngine)
|
||||||
add_subdirectory(Clipboard)
|
add_subdirectory(Clipboard)
|
||||||
|
add_subdirectory(ConfigServer)
|
||||||
add_subdirectory(CrashDaemon)
|
add_subdirectory(CrashDaemon)
|
||||||
add_subdirectory(DHCPClient)
|
add_subdirectory(DHCPClient)
|
||||||
add_subdirectory(EchoServer)
|
add_subdirectory(EchoServer)
|
||||||
|
|
18
Userland/Services/ConfigServer/CMakeLists.txt
Normal file
18
Userland/Services/ConfigServer/CMakeLists.txt
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
serenity_component(
|
||||||
|
ConfigServer
|
||||||
|
REQUIRED
|
||||||
|
TARGETS ConfigServer
|
||||||
|
)
|
||||||
|
|
||||||
|
compile_ipc(ConfigServer.ipc ConfigServerEndpoint.h)
|
||||||
|
compile_ipc(ConfigClient.ipc ConfigClientEndpoint.h)
|
||||||
|
|
||||||
|
set(SOURCES
|
||||||
|
ClientConnection.cpp
|
||||||
|
main.cpp
|
||||||
|
ConfigServerEndpoint.h
|
||||||
|
ConfigClientEndpoint.h
|
||||||
|
)
|
||||||
|
|
||||||
|
serenity_bin(ConfigServer)
|
||||||
|
target_link_libraries(ConfigServer LibIPC)
|
72
Userland/Services/ConfigServer/ClientConnection.cpp
Normal file
72
Userland/Services/ConfigServer/ClientConnection.cpp
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ClientConnection.h"
|
||||||
|
#include <ConfigServer/ConfigClientEndpoint.h>
|
||||||
|
#include <LibCore/ConfigFile.h>
|
||||||
|
|
||||||
|
namespace ConfigServer {
|
||||||
|
|
||||||
|
static HashMap<int, RefPtr<ClientConnection>> s_connections;
|
||||||
|
|
||||||
|
ClientConnection::ClientConnection(NonnullRefPtr<Core::LocalSocket> client_socket, int client_id)
|
||||||
|
: IPC::ClientConnection<ConfigClientEndpoint, ConfigServerEndpoint>(*this, move(client_socket), client_id)
|
||||||
|
{
|
||||||
|
s_connections.set(client_id, *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientConnection::~ClientConnection()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientConnection::die()
|
||||||
|
{
|
||||||
|
s_connections.remove(client_id());
|
||||||
|
}
|
||||||
|
|
||||||
|
Messages::ConfigServer::ReadStringValueResponse ClientConnection::read_string_value(String const& domain, String const& group, String const& key)
|
||||||
|
{
|
||||||
|
auto config = Core::ConfigFile::open_for_app(domain);
|
||||||
|
if (!config->has_key(group, key))
|
||||||
|
return Optional<String> {};
|
||||||
|
return Optional<String> { config->read_entry(group, key) };
|
||||||
|
}
|
||||||
|
|
||||||
|
Messages::ConfigServer::ReadI32ValueResponse ClientConnection::read_i32_value(String const& domain, String const& group, String const& key)
|
||||||
|
{
|
||||||
|
auto config = Core::ConfigFile::open_for_app(domain);
|
||||||
|
if (!config->has_key(group, key))
|
||||||
|
return Optional<i32> {};
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
auto config = Core::ConfigFile::open_for_app(domain);
|
||||||
|
if (!config->has_key(group, key))
|
||||||
|
return Optional<bool> {};
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
auto config = Core::ConfigFile::open_for_app(domain, Core::ConfigFile::AllowWriting::Yes);
|
||||||
|
config->write_entry(group, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientConnection::write_i32_value(String const& domain, String const& group, String const& key, i32 value)
|
||||||
|
{
|
||||||
|
auto config = Core::ConfigFile::open_for_app(domain, Core::ConfigFile::AllowWriting::Yes);
|
||||||
|
config->write_num_entry(group, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientConnection::write_bool_value(String const& domain, String const& group, String const& key, bool value)
|
||||||
|
{
|
||||||
|
auto config = Core::ConfigFile::open_for_app(domain, Core::ConfigFile::AllowWriting::Yes);
|
||||||
|
config->write_bool_entry(group, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
34
Userland/Services/ConfigServer/ClientConnection.h
Normal file
34
Userland/Services/ConfigServer/ClientConnection.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <LibIPC/ClientConnection.h>
|
||||||
|
|
||||||
|
#include <ConfigServer/ConfigClientEndpoint.h>
|
||||||
|
#include <ConfigServer/ConfigServerEndpoint.h>
|
||||||
|
|
||||||
|
namespace ConfigServer {
|
||||||
|
|
||||||
|
class ClientConnection final : public IPC::ClientConnection<ConfigClientEndpoint, ConfigServerEndpoint> {
|
||||||
|
C_OBJECT(ClientConnection)
|
||||||
|
public:
|
||||||
|
~ClientConnection() override;
|
||||||
|
|
||||||
|
virtual void die() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit ClientConnection(NonnullRefPtr<Core::LocalSocket>, int client_id);
|
||||||
|
|
||||||
|
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;
|
||||||
|
virtual void write_string_value([[maybe_unused]] String const& domain, [[maybe_unused]] String const& group, [[maybe_unused]] String const& key, [[maybe_unused]] String const& value) override;
|
||||||
|
virtual void write_i32_value([[maybe_unused]] String const& domain, [[maybe_unused]] String const& group, [[maybe_unused]] String const& key, [[maybe_unused]] i32 value) override;
|
||||||
|
virtual void write_bool_value([[maybe_unused]] String const& domain, [[maybe_unused]] String const& group, [[maybe_unused]] String const& key, [[maybe_unused]] bool value) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
3
Userland/Services/ConfigServer/ConfigClient.ipc
Normal file
3
Userland/Services/ConfigServer/ConfigClient.ipc
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
endpoint ConfigClient
|
||||||
|
{
|
||||||
|
}
|
10
Userland/Services/ConfigServer/ConfigServer.ipc
Normal file
10
Userland/Services/ConfigServer/ConfigServer.ipc
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
endpoint ConfigServer
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
|
||||||
|
write_string_value(String domain, String group, String key, String value) =|
|
||||||
|
write_i32_value(String domain, String group, String key, i32 value) =|
|
||||||
|
write_bool_value(String domain, String group, String key, bool value) =|
|
||||||
|
}
|
43
Userland/Services/ConfigServer/main.cpp
Normal file
43
Userland/Services/ConfigServer/main.cpp
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ClientConnection.h"
|
||||||
|
#include <LibCore/LocalServer.h>
|
||||||
|
#include <LibCore/StandardPaths.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
int main(int, char**)
|
||||||
|
{
|
||||||
|
if (pledge("stdio accept rpath wpath cpath", nullptr) < 0) {
|
||||||
|
perror("pledge");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unveil(Core::StandardPaths::config_directory().characters(), "rwc") < 0) {
|
||||||
|
perror("unveil");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
unveil(nullptr, nullptr);
|
||||||
|
|
||||||
|
Core::EventLoop event_loop;
|
||||||
|
auto server = Core::LocalServer::construct();
|
||||||
|
|
||||||
|
bool ok = server->take_over_from_system_server();
|
||||||
|
VERIFY(ok);
|
||||||
|
server->on_ready_to_accept = [&] {
|
||||||
|
auto client_socket = server->accept();
|
||||||
|
if (!client_socket) {
|
||||||
|
dbgln("ConfigServer: accept failed.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
static int s_next_client_id = 0;
|
||||||
|
int client_id = ++s_next_client_id;
|
||||||
|
IPC::new_client_connection<ConfigServer::ClientConnection>(client_socket.release_nonnull(), client_id);
|
||||||
|
};
|
||||||
|
|
||||||
|
return event_loop.exec();
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue