
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
203 lines
5.8 KiB
C
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;
|
|
}
|