wireplumber/lib/wp/configuration.c
Julian Bouzas 77ec4c548c lib: introduce WpConfiguration
The purpose of this change is to have a generic API that allows modules to read
configuration data from files under a specific directory. Since we can have many
types of configuration files, this new class maps file extensions with generic
parsers defined in the modules, giving modules full freedom to parse any kind of
data.
2019-12-04 16:38:35 -05:00

225 lines
5.7 KiB
C

/* WirePlumber
*
* Copyright © 2019 Collabora Ltd.
* @author Julian Bouzas <julian.bouzas@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
#include "configuration.h"
#include "private.h"
struct _WpConfiguration
{
GObject parent;
GPtrArray *paths;
GHashTable *parsers;
};
G_DEFINE_INTERFACE (WpConfigParser, wp_config_parser, G_TYPE_OBJECT)
static void
wp_config_parser_default_init (WpConfigParserInterface *klass)
{
}
gboolean
wp_config_parser_add_file (WpConfigParser *self, const char *location)
{
g_return_val_if_fail (WP_IS_CONFIG_PARSER (self), FALSE);
g_return_val_if_fail (WP_CONFIG_PARSER_GET_IFACE (self)->add_file, FALSE);
return WP_CONFIG_PARSER_GET_IFACE (self)->add_file (self, location);
}
gconstpointer
wp_config_parser_get_matched_data (WpConfigParser *self, gpointer data)
{
g_return_val_if_fail (WP_IS_CONFIG_PARSER (self), NULL);
g_return_val_if_fail (WP_CONFIG_PARSER_GET_IFACE (self)->get_matched_data, NULL);
return WP_CONFIG_PARSER_GET_IFACE (self)->get_matched_data (self, data);
}
void
wp_config_parser_reset (WpConfigParser *self)
{
g_return_if_fail (WP_IS_CONFIG_PARSER (self));
g_return_if_fail (WP_CONFIG_PARSER_GET_IFACE (self)->reset);
WP_CONFIG_PARSER_GET_IFACE (self)->reset (self);
}
G_DEFINE_TYPE (WpConfiguration, wp_configuration, G_TYPE_OBJECT)
static void
wp_configuration_finalize (GObject * obj)
{
WpConfiguration * self = WP_CONFIGURATION (obj);
g_clear_pointer (&self->paths, g_ptr_array_unref);
g_clear_pointer (&self->parsers, g_hash_table_unref);
G_OBJECT_CLASS (wp_configuration_parent_class)->finalize (obj);
}
static void
wp_configuration_init (WpConfiguration * self)
{
self->paths = g_ptr_array_new_with_free_func (g_free);
self->parsers = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
g_object_unref);
}
static void
wp_configuration_class_init (WpConfigurationClass * klass)
{
GObjectClass *object_class = (GObjectClass *) klass;
object_class->finalize = wp_configuration_finalize;
}
WpConfiguration *
wp_configuration_get_instance (WpCore *core)
{
WpConfiguration *self;
g_return_val_if_fail (WP_IS_CORE (core), NULL);
self = wp_core_find_object (core, (GEqualFunc) WP_IS_CONFIGURATION, NULL);
if (!self) {
self = g_object_new (WP_TYPE_CONFIGURATION, NULL);
wp_core_register_object (core, g_object_ref (self));
}
return self;
}
void
wp_configuration_add_path (WpConfiguration *self, const char *path)
{
guint i;
g_return_if_fail (self);
g_return_if_fail (WP_IS_CONFIGURATION (self));
/* Make sure the path is not already added */
for (i = 0; i < self->paths->len; i++) {
const char *p = g_ptr_array_index(self->paths, i);
if (g_strcmp0(p, path) == 0)
return;
}
g_ptr_array_add (self->paths, g_strdup (path));
}
void
wp_configuration_remove_path (WpConfiguration *self, const char *path)
{
guint i;
g_return_if_fail (self);
g_return_if_fail (WP_IS_CONFIGURATION (self));
/* Find the path index */
for (i = 0; i < self->paths->len; i++) {
const char *p = g_ptr_array_index(self->paths, i);
if (g_strcmp0(p, path) == 0)
break;
}
/* Only remove the path if the index is valid */
if (i < self->paths->len)
g_ptr_array_remove_index (self->paths, i);
}
gboolean
wp_configuration_add_extension (WpConfiguration *self, const gchar * extension,
GType parser_type)
{
g_return_val_if_fail (self, FALSE);
g_return_val_if_fail (WP_IS_CONFIGURATION (self), FALSE);
/* create the parser */
g_autoptr (WpConfigParser) parser = g_object_new (parser_type, FALSE);
g_return_val_if_fail (WP_IS_CONFIG_PARSER (parser), FALSE);
return g_hash_table_insert (self->parsers, g_strdup (extension),
g_steal_pointer (&parser));
}
gboolean
wp_configuration_remove_extension (WpConfiguration *self,
const gchar * extension)
{
g_return_val_if_fail (self, FALSE);
g_return_val_if_fail (WP_IS_CONFIGURATION (self), FALSE);
return g_hash_table_remove (self->parsers, extension);
}
WpConfigParser *
wp_configuration_get_parser (WpConfiguration *self, const char *extension)
{
WpConfigParser *parser = NULL;
g_return_val_if_fail (self, NULL);
g_return_val_if_fail (WP_IS_CONFIGURATION (self), NULL);
parser = g_hash_table_lookup (self->parsers, extension);
return parser ? g_object_ref (parser) : NULL;
}
void
wp_configuration_reload (WpConfiguration *self, const char *extension)
{
guint i;
const char *path = NULL;
GDir* conf_dir = NULL;
GError* error = NULL;
const gchar *file_name = NULL;
g_autofree gchar *ext = NULL;
g_autofree gchar *location = NULL;
g_return_if_fail (self);
g_return_if_fail (WP_IS_CONFIGURATION (self));
/* Get the parser for the extension */
WpConfigParser *parser = g_hash_table_lookup (self->parsers, extension);
if (!parser) {
g_warning ("Could not find parser for extension '%s'", extension);
return;
}
/* Reset the parser */
wp_config_parser_reset (parser);
/* Load extension files in all paths */
for (i = 0; i < self->paths->len; i++) {
/* Get the path */
path = g_ptr_array_index(self->paths, i);
/* Open the directory */
conf_dir = g_dir_open (path, 0, &error);
if (!conf_dir) {
g_warning ("Could not open configuration path '%s'", path);
continue;
}
/* Parse each configuration file matching the extension */
ext = g_strdup_printf (".%s", extension);
while ((file_name = g_dir_read_name (conf_dir))) {
/* Only parse files that have the proper extension */
if (g_str_has_suffix (file_name, ext)) {
location = g_build_filename (path, file_name, NULL);
if (!wp_config_parser_add_file (parser, location))
g_warning ("Failed to parse file '%s'", location);
}
}
/* Close the directory */
g_dir_close (conf_dir);
}
}