Files
wireplumber/modules/module-lua-scripting/api/require.c
George Kiagiadakis c7cb193588 core: introduce the notion of provided features on components
Each component can optionally "provide" a feature, which is basically
a string that describes the feature (ex. "support.dbus"). If the
component loads successfully, the feature is marked as provided and
can be tested for its presence with wp_core_test_feature()
2023-06-20 12:39:29 +03:00

178 lines
5.0 KiB
C

/* WirePlumber
*
* Copyright © 2021 Collabora Ltd.
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
#include <wp/wp.h>
#include <wplua/wplua.h>
#define WP_LOCAL_LOG_TOPIC log_topic_lua_scripting
WP_LOG_TOPIC_EXTERN (log_topic_lua_scripting)
struct _WpRequireApiTransition
{
WpTransition parent;
GPtrArray *apis;
guint pending_plugins;
};
enum {
STEP_LOAD_PLUGINS = WP_TRANSITION_STEP_CUSTOM_START,
};
G_DECLARE_FINAL_TYPE (WpRequireApiTransition, wp_require_api_transition,
WP, REQUIRE_API_TRANSITION, WpTransition)
G_DEFINE_TYPE (WpRequireApiTransition, wp_require_api_transition, WP_TYPE_TRANSITION)
static void
wp_require_api_transition_init (WpRequireApiTransition * self)
{
self->apis = g_ptr_array_new_with_free_func (g_free);
}
static void
wp_require_api_transition_finalize (GObject * object)
{
WpRequireApiTransition *self = WP_REQUIRE_API_TRANSITION (object);
g_clear_pointer (&self->apis, g_ptr_array_unref);
G_OBJECT_CLASS (wp_require_api_transition_parent_class)->finalize (object);
}
static guint
wp_require_api_transition_get_next_step (WpTransition * transition, guint step)
{
WpRequireApiTransition *self = WP_REQUIRE_API_TRANSITION (transition);
switch (step) {
case WP_TRANSITION_STEP_NONE: return STEP_LOAD_PLUGINS;
case STEP_LOAD_PLUGINS:
return (self->pending_plugins > 0) ?
STEP_LOAD_PLUGINS : WP_TRANSITION_STEP_NONE;
default:
g_return_val_if_reached (WP_TRANSITION_STEP_ERROR);
}
}
static void
on_plugin_loaded (WpCore * core, GAsyncResult * res,
WpRequireApiTransition *self)
{
GError *error = NULL;
if (!wp_core_load_component_finish (core, res, &error)) {
wp_transition_return_error (WP_TRANSITION (self), error);
return;
}
--self->pending_plugins;
wp_transition_advance (WP_TRANSITION (self));
}
static void
wp_require_api_transition_execute_step (WpTransition * transition, guint step)
{
WpRequireApiTransition *self = WP_REQUIRE_API_TRANSITION (transition);
WpCore *core = wp_transition_get_source_object (transition);
switch (step) {
case STEP_LOAD_PLUGINS:
wp_debug_object (self, "Loading plugins...");
for (guint i = 0; i < self->apis->len; i++) {
const gchar *api_name = g_ptr_array_index (self->apis, i);
g_autoptr (WpPlugin) plugin = wp_plugin_find (core, api_name);
if (!plugin) {
gchar module_name[50];
g_snprintf (module_name, sizeof (module_name),
"libwireplumber-module-%s", api_name);
self->pending_plugins++;
wp_core_load_component (core, module_name, "module", NULL, NULL, NULL,
(GAsyncReadyCallback) on_plugin_loaded, self);
}
}
wp_transition_advance (transition);
break;
case WP_TRANSITION_STEP_ERROR:
break;
default:
g_assert_not_reached ();
}
}
static void
wp_require_api_transition_class_init (WpRequireApiTransitionClass * klass)
{
GObjectClass * object_class = (GObjectClass *) klass;
WpTransitionClass * transition_class = (WpTransitionClass *) klass;
object_class->finalize = wp_require_api_transition_finalize;
transition_class->get_next_step = wp_require_api_transition_get_next_step;
transition_class->execute_step = wp_require_api_transition_execute_step;
}
static void
on_require_api_transition_done (WpCore * core, GAsyncResult * res, gpointer data)
{
g_autoptr (GClosure) closure = data;
g_autoptr (GError) error = NULL;
if (!wp_transition_finish (res, &error)) {
wp_warning ("Core.require_api failed: %s", error->message);
wp_core_idle_add (core, NULL, G_SOURCE_FUNC (core_disconnect), core, NULL);
return;
}
WpRequireApiTransition *t = WP_REQUIRE_API_TRANSITION (res);
g_autoptr (GArray) params = g_array_new (FALSE, TRUE, sizeof (GValue));
g_array_set_clear_func (params, (GDestroyNotify) g_value_unset);
g_array_set_size (params, t->apis->len);
for (guint i = 0; i < t->apis->len; i++) {
const gchar *api_name = g_ptr_array_index (t->apis, i);
g_autoptr (WpPlugin) plugin = wp_plugin_find (core, api_name);
g_value_init_from_instance (&g_array_index (params, GValue, i), plugin);
}
g_closure_invoke (closure, NULL,
params->len, (const GValue *) params->data, NULL);
g_closure_invalidate (closure);
}
static int
wp_require_api_transition_new_from_lua (lua_State *L, WpCore * core)
{
int n_args = lua_gettop (L);
wp_info("n_args = %d", n_args);
for (int i = 1; i < n_args; i++)
luaL_checktype (L, i, LUA_TSTRING);
luaL_checktype (L, n_args, LUA_TFUNCTION);
GClosure *closure = wplua_function_to_closure (L, n_args);
g_closure_ref (closure);
g_closure_sink (closure);
WpRequireApiTransition *t = (WpRequireApiTransition *)
wp_transition_new (wp_require_api_transition_get_type (), core, NULL,
(GAsyncReadyCallback) on_require_api_transition_done, closure);
for (int i = 1; i < n_args; i++) {
const char * api_name = lua_tostring (L, i);
g_ptr_array_add (t->apis, g_strdup_printf ("%s-api", api_name));
}
wp_transition_advance (WP_TRANSITION (t));
return 0;
}