Files
wireplumber/modules/module-lua-scripting/module.c
George Kiagiadakis 17a257ddbe wplua: move under modules/module-lua-scripting
It's unlikely that wplua will ever be useful outside the context
of module-lua-scripting, so let's move it to keep all the code in one place
2022-03-24 09:47:59 +02:00

203 lines
5.8 KiB
C

/* WirePlumber
*
* Copyright © 2020 Collabora Ltd.
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
#include <wp/wp.h>
#include <wplua/wplua.h>
#include <pipewire/keys.h>
void wp_lua_scripting_api_init (lua_State *L);
gboolean wp_lua_scripting_load_configuration (const gchar * conf_file,
WpCore * core, GError ** error);
struct _WpLuaScriptingPlugin
{
WpComponentLoader parent;
GArray *scripts;
WpCore *export_core;
lua_State *L;
};
struct ScriptData
{
gchar *filename;
GVariant *args;
};
static void
script_data_clear (struct ScriptData * d)
{
g_clear_pointer (&d->filename, g_free);
g_clear_pointer (&d->args, g_variant_unref);
}
static gboolean
execute_script (lua_State *L, struct ScriptData * s, GError ** error)
{
int nargs = 0;
if (s->args) {
wplua_gvariant_to_lua (L, s->args);
nargs++;
}
return wplua_load_path (L, s->filename, nargs, 0, error);
}
G_DECLARE_FINAL_TYPE (WpLuaScriptingPlugin, wp_lua_scripting_plugin,
WP, LUA_SCRIPTING_PLUGIN, WpComponentLoader)
G_DEFINE_TYPE (WpLuaScriptingPlugin, wp_lua_scripting_plugin,
WP_TYPE_COMPONENT_LOADER)
static void
wp_lua_scripting_plugin_init (WpLuaScriptingPlugin * self)
{
self->scripts = g_array_new (FALSE, TRUE, sizeof (struct ScriptData));
g_array_set_clear_func (self->scripts, (GDestroyNotify) script_data_clear);
}
static void
wp_lua_scripting_plugin_finalize (GObject * object)
{
WpLuaScriptingPlugin * self = WP_LUA_SCRIPTING_PLUGIN (object);
g_clear_pointer (&self->scripts, g_array_unref);
G_OBJECT_CLASS (wp_lua_scripting_plugin_parent_class)->finalize (object);
}
static void
wp_lua_scripting_plugin_enable (WpPlugin * plugin, WpTransition * transition)
{
WpLuaScriptingPlugin * self = WP_LUA_SCRIPTING_PLUGIN (plugin);
g_autoptr (WpCore) core = wp_object_get_core (WP_OBJECT (plugin));
/* initialize secondary connection to pipewire */
self->export_core =
g_object_get_data (G_OBJECT (core), "wireplumber.export-core");
if (self->export_core)
g_object_ref (self->export_core);
/* init lua engine */
self->L = wplua_new ();
lua_pushliteral (self->L, "wireplumber_core");
lua_pushlightuserdata (self->L, core);
lua_settable (self->L, LUA_REGISTRYINDEX);
lua_pushliteral (self->L, "wireplumber_export_core");
lua_pushlightuserdata (self->L, self->export_core);
lua_settable (self->L, LUA_REGISTRYINDEX);
wp_lua_scripting_api_init (self->L);
wplua_enable_sandbox (self->L, WP_LUA_SANDBOX_ISOLATE_ENV);
/* execute scripts that were queued in for loading */
for (guint i = 0; i < self->scripts->len; i++) {
GError * error = NULL;
struct ScriptData * s = &g_array_index (self->scripts, struct ScriptData, i);
if (!execute_script (self->L, s, &error)) {
wp_transition_return_error (transition, error);
return;
}
}
wp_object_update_features (WP_OBJECT (self), WP_PLUGIN_FEATURE_ENABLED, 0);
}
static void
wp_lua_scripting_plugin_disable (WpPlugin * plugin)
{
WpLuaScriptingPlugin * self = WP_LUA_SCRIPTING_PLUGIN (plugin);
g_clear_pointer (&self->L, wplua_free);
g_clear_object (&self->export_core);
}
static gboolean
wp_lua_scripting_plugin_supports_type (WpComponentLoader * cl,
const gchar * type)
{
return (!g_strcmp0 (type, "script/lua") || !g_strcmp0 (type, "config/lua"));
}
static gchar *
find_script (const gchar * script, gboolean daemon)
{
if ((!daemon || g_path_is_absolute (script)) &&
g_file_test (script, G_FILE_TEST_IS_REGULAR))
return g_strdup (script);
return wp_find_file (WP_LOOKUP_DIR_ENV_DATA |
WP_LOOKUP_DIR_XDG_CONFIG_HOME |
WP_LOOKUP_DIR_ETC |
WP_LOOKUP_DIR_PREFIX_SHARE,
script, "scripts");
}
static gboolean
wp_lua_scripting_plugin_load (WpComponentLoader * cl, const gchar * component,
const gchar * type, GVariant * args, GError ** error)
{
WpLuaScriptingPlugin * self = WP_LUA_SCRIPTING_PLUGIN (cl);
g_autoptr (WpCore) core = wp_object_get_core (WP_OBJECT (cl));
/* interpret component as a script */
if (!g_strcmp0 (type, "script/lua")) {
g_autoptr (WpProperties) p = wp_core_get_properties (core);
const gchar *str = wp_properties_get (p, "wireplumber.daemon");
gboolean daemon = !g_strcmp0 (str, "true");
struct ScriptData s = {0};
s.filename = find_script (component, daemon);
if (!s.filename) {
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
"Could not locate script '%s'", component);
return FALSE;
}
if (args && g_variant_is_of_type (args, G_VARIANT_TYPE_VARDICT))
s.args = g_variant_ref (args);
/* keep in a list and delay loading until the plugin is enabled */
g_array_append_val (self->scripts, s);
return self->L ? execute_script (self->L, &s, error) : TRUE;
}
/* interpret component as a configuration file */
else if (!g_strcmp0 (type, "config/lua")) {
return wp_lua_scripting_load_configuration (component, core, error);
}
g_return_val_if_reached (FALSE);
}
static void
wp_lua_scripting_plugin_class_init (WpLuaScriptingPluginClass * klass)
{
GObjectClass *object_class = (GObjectClass *) klass;
WpPluginClass *plugin_class = (WpPluginClass *) klass;
WpComponentLoaderClass *cl_class = (WpComponentLoaderClass *) klass;
object_class->finalize = wp_lua_scripting_plugin_finalize;
plugin_class->enable = wp_lua_scripting_plugin_enable;
plugin_class->disable = wp_lua_scripting_plugin_disable;
cl_class->supports_type = wp_lua_scripting_plugin_supports_type;
cl_class->load = wp_lua_scripting_plugin_load;
}
WP_PLUGIN_EXPORT gboolean
wireplumber__module_init (WpCore * core, GVariant * args, GError ** error)
{
wp_plugin_register (g_object_new (wp_lua_scripting_plugin_get_type (),
"name", "lua-scripting",
"core", core,
NULL));
return TRUE;
}