core: change the component arguments to be WpSpaJson instead of GVariant

This allows us to pass entire JSON objects from the config file
down to the modules / scripts without any conversion
This commit is contained in:
George Kiagiadakis 2023-05-25 18:29:58 +03:00
parent d755ec4f20
commit 5c3032c064
20 changed files with 63 additions and 59 deletions

View file

@ -31,7 +31,7 @@ WP_DEFINE_LOCAL_LOG_TOPIC ("wp-comp-loader")
*/ */
#define WP_MODULE_INIT_SYMBOL "wireplumber__module_init" #define WP_MODULE_INIT_SYMBOL "wireplumber__module_init"
typedef GObject *(*WpModuleInitFunc) (WpCore *, GVariant *, GError **); typedef GObject *(*WpModuleInitFunc) (WpCore *, WpSpaJson *, GError **);
G_DEFINE_ABSTRACT_TYPE (WpComponentLoader, wp_component_loader, WP_TYPE_PLUGIN) G_DEFINE_ABSTRACT_TYPE (WpComponentLoader, wp_component_loader, WP_TYPE_PLUGIN)
@ -47,7 +47,7 @@ wp_component_loader_class_init (WpComponentLoaderClass * klass)
static GObject * static GObject *
load_module (WpCore * core, const gchar * module_name, load_module (WpCore * core, const gchar * module_name,
GVariant * args, GError ** error) WpSpaJson * args, GError ** error)
{ {
g_autofree gchar *module_path = NULL; g_autofree gchar *module_path = NULL;
GModule *gmodule; GModule *gmodule;
@ -99,7 +99,7 @@ wp_component_loader_find (WpCore * core, const gchar * type)
static void static void
wp_component_loader_load (WpComponentLoader * self, const gchar * component, wp_component_loader_load (WpComponentLoader * self, const gchar * component,
const gchar * type, GVariant * args, GAsyncReadyCallback callback, const gchar * type, WpSpaJson * args, GAsyncReadyCallback callback,
gpointer data) gpointer data)
{ {
g_return_if_fail (WP_IS_COMPONENT_LOADER (self)); g_return_if_fail (WP_IS_COMPONENT_LOADER (self));
@ -132,17 +132,16 @@ on_object_loaded (WpObject *object, GAsyncResult *res, gpointer data)
* \param self the core * \param self the core
* \param component the module name or file name * \param component the module name or file name
* \param type the type of the component * \param type the type of the component
* \param args (transfer floating)(nullable): additional arguments for the component, * \param args (transfer none)(nullable): additional arguments for the component,
* usually a dict or a string * expected to be a JSON object
* \param callback (scope async): the callback to call when the operation is done * \param callback (scope async): the callback to call when the operation is done
* \param data (closure): data to pass to \a callback * \param data (closure): data to pass to \a callback
*/ */
void void
wp_core_load_component (WpCore * self, const gchar * component, wp_core_load_component (WpCore * self, const gchar * component,
const gchar * type, GVariant * args, GAsyncReadyCallback callback, const gchar * type, WpSpaJson * args, GAsyncReadyCallback callback,
gpointer data) gpointer data)
{ {
g_autoptr (GVariant) args_ref = args ? g_variant_ref_sink (args) : NULL;
g_autoptr (GTask) task = NULL; g_autoptr (GTask) task = NULL;
g_autoptr (WpComponentLoader) c = NULL; g_autoptr (WpComponentLoader) c = NULL;
@ -153,7 +152,7 @@ wp_core_load_component (WpCore * self, const gchar * component,
g_autoptr (GObject) o = NULL; g_autoptr (GObject) o = NULL;
/* load Module */ /* load Module */
o = load_module (self, component, args_ref, &error); o = load_module (self, component, args, &error);
if (!o) { if (!o) {
g_task_return_error (task, g_steal_pointer (&error)); g_task_return_error (task, g_steal_pointer (&error));
return; return;

View file

@ -10,6 +10,7 @@
#define __WIREPLUMBER_COMPONENT_LOADER_H__ #define __WIREPLUMBER_COMPONENT_LOADER_H__
#include "plugin.h" #include "plugin.h"
#include "spa-json.h"
G_BEGIN_DECLS G_BEGIN_DECLS
@ -29,7 +30,7 @@ struct _WpComponentLoaderClass
gboolean (*supports_type) (WpComponentLoader * self, const gchar * type); gboolean (*supports_type) (WpComponentLoader * self, const gchar * type);
void (*load) (WpComponentLoader * self, const gchar * component, void (*load) (WpComponentLoader * self, const gchar * component,
const gchar * type, GVariant * args, GAsyncReadyCallback callback, const gchar * type, WpSpaJson * args, GAsyncReadyCallback callback,
gpointer data); gpointer data);
/*< private >*/ /*< private >*/

View file

@ -12,6 +12,7 @@
#include <gio/gio.h> #include <gio/gio.h>
#include "defs.h" #include "defs.h"
#include "properties.h" #include "properties.h"
#include "spa-json.h"
G_BEGIN_DECLS G_BEGIN_DECLS
@ -49,7 +50,7 @@ gchar *wp_core_get_vm_type (WpCore *self);
WP_API WP_API
void wp_core_load_component (WpCore * self, const gchar * component, void wp_core_load_component (WpCore * self, const gchar * component,
const gchar * type, GVariant * args, GAsyncReadyCallback callback, const gchar * type, WpSpaJson * args, GAsyncReadyCallback callback,
gpointer data); gpointer data);
WP_API WP_API

View file

@ -307,7 +307,7 @@ wp_default_nodes_api_class_init (WpDefaultNodesApiClass * klass)
} }
WP_PLUGIN_EXPORT GObject * WP_PLUGIN_EXPORT GObject *
wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) wireplumber__module_init (WpCore * core, WpSpaJson * args, GError ** error)
{ {
return G_OBJECT (g_object_new (wp_default_nodes_api_get_type (), return G_OBJECT (g_object_new (wp_default_nodes_api_get_type (),
"name", "default-nodes-api", "name", "default-nodes-api",

View file

@ -204,7 +204,7 @@ wp_file_monitor_api_class_init (WpFileMonitorApiClass * klass)
} }
WP_PLUGIN_EXPORT GObject * WP_PLUGIN_EXPORT GObject *
wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) wireplumber__module_init (WpCore * core, WpSpaJson * args, GError ** error)
{ {
return G_OBJECT (g_object_new (wp_file_monitor_api_get_type (), return G_OBJECT (g_object_new (wp_file_monitor_api_get_type (),
"name", "file-monitor-api", "name", "file-monitor-api",

View file

@ -134,7 +134,7 @@ wp_logind_class_init (WpLogindClass * klass)
} }
WP_PLUGIN_EXPORT GObject * WP_PLUGIN_EXPORT GObject *
wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) wireplumber__module_init (WpCore * core, WpSpaJson * args, GError ** error)
{ {
return G_OBJECT (g_object_new (wp_logind_get_type (), return G_OBJECT (g_object_new (wp_logind_get_type (),
"name", NAME, "name", NAME,

View file

@ -173,7 +173,7 @@ on_script_loaded (WpObject *object, GAsyncResult *res, gpointer data)
static void static void
wp_lua_scripting_plugin_load (WpComponentLoader * cl, const gchar * component, wp_lua_scripting_plugin_load (WpComponentLoader * cl, const gchar * component,
const gchar * type, GVariant * args, GAsyncReadyCallback callback, const gchar * type, WpSpaJson * args, GAsyncReadyCallback callback,
gpointer data) gpointer data)
{ {
WpLuaScriptingPlugin * self = WP_LUA_SCRIPTING_PLUGIN (cl); WpLuaScriptingPlugin * self = WP_LUA_SCRIPTING_PLUGIN (cl);
@ -238,7 +238,7 @@ wp_lua_scripting_plugin_class_init (WpLuaScriptingPluginClass * klass)
} }
WP_PLUGIN_EXPORT GObject * WP_PLUGIN_EXPORT GObject *
wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) wireplumber__module_init (WpCore * core, WpSpaJson * args, GError ** error)
{ {
return G_OBJECT (g_object_new (wp_lua_scripting_plugin_get_type (), return G_OBJECT (g_object_new (wp_lua_scripting_plugin_get_type (),
"name", "lua-scripting", "name", "lua-scripting",

View file

@ -29,7 +29,7 @@ struct _WpLuaScript
lua_State *L; lua_State *L;
gchar *filename; gchar *filename;
GVariant *args; WpSpaJson *args;
}; };
enum { enum {
@ -64,7 +64,7 @@ wp_lua_script_finalize (GObject * object)
wp_lua_script_cleanup (self); wp_lua_script_cleanup (self);
g_clear_pointer (&self->L, wplua_unref); g_clear_pointer (&self->L, wplua_unref);
g_clear_pointer (&self->filename, g_free); g_clear_pointer (&self->filename, g_free);
g_clear_pointer (&self->args, g_variant_unref); g_clear_pointer (&self->args, wp_spa_json_unref);
G_OBJECT_CLASS (wp_lua_script_parent_class)->finalize (object); G_OBJECT_CLASS (wp_lua_script_parent_class)->finalize (object);
} }
@ -86,7 +86,7 @@ wp_lua_script_set_property (GObject * object, guint property_id,
self->filename = g_value_dup_string (value); self->filename = g_value_dup_string (value);
break; break;
case PROP_ARGUMENTS: case PROP_ARGUMENTS:
self->args = g_value_dup_variant (value); self->args = g_value_dup_boxed (value);
break; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@ -231,7 +231,7 @@ wp_lua_script_enable (WpPlugin * plugin, WpTransition * transition)
/* push script arguments */ /* push script arguments */
if (self->args) { if (self->args) {
wplua_gvariant_to_lua (self->L, self->args); wplua_pushboxed (self->L, WP_TYPE_SPA_JSON, wp_spa_json_ref (self->args));
nargs++; nargs++;
} }
@ -282,7 +282,7 @@ wp_lua_script_class_init (WpLuaScriptClass * klass)
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (object_class, PROP_ARGUMENTS, g_object_class_install_property (object_class, PROP_ARGUMENTS,
g_param_spec_variant ("arguments", "arguments", "arguments", g_param_spec_boxed ("arguments", "arguments", "arguments",
G_VARIANT_TYPE_VARDICT, NULL, WP_TYPE_SPA_JSON,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
} }

View file

@ -30,6 +30,7 @@ _wplua_gboxed___index (lua_State *L)
"expected userdata storing GValue<GBoxed>"); "expected userdata storing GValue<GBoxed>");
GValue *obj_v = lua_touserdata (L, 1); GValue *obj_v = lua_touserdata (L, 1);
const gchar *key = luaL_checkstring (L, 2); const gchar *key = luaL_checkstring (L, 2);
GType type = G_VALUE_TYPE (obj_v);
lua_CFunction func = NULL; lua_CFunction func = NULL;
GHashTable *vtables; GHashTable *vtables;
@ -39,15 +40,15 @@ _wplua_gboxed___index (lua_State *L)
lua_pop (L, 1); lua_pop (L, 1);
/* search in registered vtables */ /* search in registered vtables */
if (!func) { while (!func && type) {
GType type = G_VALUE_TYPE (obj_v); luaL_Reg *reg = g_hash_table_lookup (vtables, GUINT_TO_POINTER (type));
while (!func && type) { func = find_method_in_luaL_Reg (reg, key);
luaL_Reg *reg = g_hash_table_lookup (vtables, GUINT_TO_POINTER (type)); type = g_type_parent (type);
func = find_method_in_luaL_Reg (reg, key);
type = g_type_parent (type);
}
} }
wp_trace_boxed (type, g_value_get_boxed (obj_v),
"indexing GBoxed, looking for '%s', found: %p", key, func);
if (func) { if (func) {
lua_pushcfunction (L, func); lua_pushcfunction (L, func);
return 1; return 1;

View file

@ -617,7 +617,7 @@ wp_mixer_api_class_init (WpMixerApiClass * klass)
} }
WP_PLUGIN_EXPORT GObject * WP_PLUGIN_EXPORT GObject *
wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) wireplumber__module_init (WpCore * core, WpSpaJson * args, GError ** error)
{ {
return G_OBJECT (g_object_new (wp_mixer_api_get_type (), return G_OBJECT (g_object_new (wp_mixer_api_get_type (),
"name", "mixer-api", "name", "mixer-api",

View file

@ -305,7 +305,7 @@ wp_portal_permissionstore_plugin_class_init (
} }
WP_PLUGIN_EXPORT GObject * WP_PLUGIN_EXPORT GObject *
wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) wireplumber__module_init (WpCore * core, WpSpaJson * args, GError ** error)
{ {
return G_OBJECT (g_object_new ( return G_OBJECT (g_object_new (
wp_portal_permissionstore_plugin_get_type(), wp_portal_permissionstore_plugin_get_type(),

View file

@ -267,7 +267,7 @@ wp_reserve_device_plugin_class_init (WpReserveDevicePluginClass * klass)
} }
WP_PLUGIN_EXPORT GObject * WP_PLUGIN_EXPORT GObject *
wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) wireplumber__module_init (WpCore * core, WpSpaJson * args, GError ** error)
{ {
return G_OBJECT (g_object_new (wp_reserve_device_plugin_get_type (), return G_OBJECT (g_object_new (wp_reserve_device_plugin_get_type (),
"name", "reserve-device", "name", "reserve-device",

View file

@ -339,15 +339,15 @@ wp_settings_plugin_class_init (WpSettingsPluginClass * klass)
} }
WP_PLUGIN_EXPORT GObject * WP_PLUGIN_EXPORT GObject *
wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) wireplumber__module_init (WpCore * core, WpSpaJson * args, GError ** error)
{ {
const gchar *metadata_name = "sm-settings"; g_autofree gchar *metadata_name = NULL;
if (args) if (args)
metadata_name = g_variant_get_string (args, NULL); wp_spa_json_object_get (args, "metadata-name", "s", &metadata_name, NULL);
return G_OBJECT (g_object_new (wp_settings_plugin_get_type (), return G_OBJECT (g_object_new (wp_settings_plugin_get_type (),
"name", "settings", "name", "settings",
"core", core, "core", core,
"metadata-name", metadata_name, "metadata-name", metadata_name ? metadata_name : "sm-settings",
NULL)); NULL));
} }

View file

@ -780,7 +780,7 @@ si_audio_adapter_linkable_init (WpSiLinkableInterface * iface)
} }
WP_PLUGIN_EXPORT GObject * WP_PLUGIN_EXPORT GObject *
wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) wireplumber__module_init (WpCore * core, WpSpaJson * args, GError ** error)
{ {
return G_OBJECT (wp_si_factory_new_simple (SI_FACTORY_NAME, return G_OBJECT (wp_si_factory_new_simple (SI_FACTORY_NAME,
si_audio_adapter_get_type ())); si_audio_adapter_get_type ()));

View file

@ -358,7 +358,7 @@ si_audio_virtual_adapter_init (WpSiAdapterInterface * iface)
} }
WP_PLUGIN_EXPORT GObject * WP_PLUGIN_EXPORT GObject *
wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) wireplumber__module_init (WpCore * core, WpSpaJson * args, GError ** error)
{ {
return G_OBJECT (wp_si_factory_new_simple (SI_FACTORY_NAME, return G_OBJECT (wp_si_factory_new_simple (SI_FACTORY_NAME,
si_audio_virtual_get_type ())); si_audio_virtual_get_type ()));

View file

@ -222,7 +222,7 @@ si_node_linkable_init (WpSiLinkableInterface * iface)
} }
WP_PLUGIN_EXPORT GObject * WP_PLUGIN_EXPORT GObject *
wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) wireplumber__module_init (WpCore * core, WpSpaJson * args, GError ** error)
{ {
return G_OBJECT (wp_si_factory_new_simple (SI_FACTORY_NAME, return G_OBJECT (wp_si_factory_new_simple (SI_FACTORY_NAME,
si_node_get_type ())); si_node_get_type ()));

View file

@ -778,7 +778,7 @@ si_standard_link_link_init (WpSiLinkInterface * iface)
} }
WP_PLUGIN_EXPORT GObject * WP_PLUGIN_EXPORT GObject *
wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) wireplumber__module_init (WpCore * core, WpSpaJson * args, GError ** error)
{ {
return G_OBJECT (wp_si_factory_new_simple (SI_FACTORY_NAME, return G_OBJECT (wp_si_factory_new_simple (SI_FACTORY_NAME,
si_standard_link_get_type ())); si_standard_link_get_type ()));

View file

@ -452,7 +452,7 @@ wp_standard_event_source_class_init (WpStandardEventSourceClass * klass)
} }
WP_PLUGIN_EXPORT GObject * WP_PLUGIN_EXPORT GObject *
wireplumber__module_init (WpCore * core, GVariant * args, GError ** error) wireplumber__module_init (WpCore * core, WpSpaJson * args, GError ** error)
{ {
return G_OBJECT (g_object_new (wp_standard_event_source_get_type (), return G_OBJECT (g_object_new (wp_standard_event_source_get_type (),
"name", "standard-event-source", "name", "standard-event-source",

View file

@ -27,8 +27,8 @@ enum WpExitCode
}; };
static gchar * exec_script = NULL; static gchar * exec_script = NULL;
static GVariantBuilder exec_args_b = static gchar *exec_args_s = NULL;
G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_VARDICT); static WpSpaJson *exec_args = NULL;
static gboolean static gboolean
parse_exec_script_arg (const gchar *option_name, const gchar *value, parse_exec_script_arg (const gchar *option_name, const gchar *value,
@ -40,16 +40,17 @@ parse_exec_script_arg (const gchar *option_name, const gchar *value,
return TRUE; return TRUE;
} }
g_auto(GStrv) tokens = g_strsplit (value, "=", 2); /* the second argument is a json object with script arguments */
if (!tokens[0] || *g_strstrip (tokens[0]) == '\0') { if (!exec_args) {
g_set_error (error, WP_DOMAIN_DAEMON, WP_EXIT_USAGE, exec_args_s = g_strdup (value);
"invalid script argument '%s'; must be in key=value format", value); exec_args = wp_spa_json_new_from_string (exec_args_s);
return FALSE; if (!exec_args || !wp_spa_json_is_object (exec_args)) {
g_set_error (error, WP_DOMAIN_DAEMON, WP_EXIT_USAGE,
"script argument must be a JSON object");
return FALSE;
}
} }
g_variant_builder_add (&exec_args_b, "{sv}", tokens[0], tokens[1] ?
g_variant_new_string (g_strstrip (tokens[1])) :
g_variant_new_boolean (TRUE));
return TRUE; return TRUE;
} }
@ -146,8 +147,7 @@ wp_init_transition_execute_step (WpTransition * transition, guint step)
} }
case STEP_ACTIVATE_SCRIPT: { case STEP_ACTIVATE_SCRIPT: {
GVariant *args = g_variant_builder_end (&exec_args_b); wp_core_load_component (core, exec_script, "script/lua", exec_args,
wp_core_load_component (core, exec_script, "script/lua", args,
(GAsyncReadyCallback) on_plugin_loaded, self); (GAsyncReadyCallback) on_plugin_loaded, self);
break; break;
} }

View file

@ -10,21 +10,23 @@
-- This is an example of an interactive script -- This is an example of an interactive script
-- --
-- Execute with: -- Execute with:
-- wpexec ./interactive.lua option1=value1 option2=value2 ... -- wpexec ./interactive.lua '{ option1 = "value1" , option2 = "value2" }' ...
-- or: -- or:
-- ./interactive.lua option1=value1 option2=value2 -- ./interactive.lua '{ option1 = "value1" , option2 = "value2" }'
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
-- --
-- Collects arguments passed in from the command line -- Collects arguments passed in from the command line
-- Assuming option1=value1 option2=value2 were passed, this will be a table -- Assuming '{ option1 = "value1" , option2 = "value2" }' were passed,
-- like this: { ["option1"] = "value1", ["option2"] = "value2" } -- this will be a table like this:
-- { ["option1"] = "value1", ["option2"] = "value2" }
-- --
local argv = ... local argv = ...
if argv then
argv = argv:parse()
print ("Command-line arguments:") print ("Command-line arguments:")
for k, v in pairs(argv) do Debug.dump_table (argv)
print ("\t" .. k .. ": " .. v)
end end
-- --