diff --git a/lib/wp/component-loader.c b/lib/wp/component-loader.c index bf59b831..424b53c3 100644 --- a/lib/wp/component-loader.c +++ b/lib/wp/component-loader.c @@ -31,7 +31,7 @@ WP_DEFINE_LOCAL_LOG_TOPIC ("wp-comp-loader") */ #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) @@ -47,7 +47,7 @@ wp_component_loader_class_init (WpComponentLoaderClass * klass) static GObject * load_module (WpCore * core, const gchar * module_name, - GVariant * args, GError ** error) + WpSpaJson * args, GError ** error) { g_autofree gchar *module_path = NULL; GModule *gmodule; @@ -99,7 +99,7 @@ wp_component_loader_find (WpCore * core, const gchar * type) static void 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) { 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 component the module name or file name * \param type the type of the component - * \param args (transfer floating)(nullable): additional arguments for the component, - * usually a dict or a string + * \param args (transfer none)(nullable): additional arguments for the component, + * expected to be a JSON object * \param callback (scope async): the callback to call when the operation is done * \param data (closure): data to pass to \a callback */ 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) { - g_autoptr (GVariant) args_ref = args ? g_variant_ref_sink (args) : NULL; g_autoptr (GTask) task = NULL; g_autoptr (WpComponentLoader) c = NULL; @@ -153,7 +152,7 @@ wp_core_load_component (WpCore * self, const gchar * component, g_autoptr (GObject) o = NULL; /* load Module */ - o = load_module (self, component, args_ref, &error); + o = load_module (self, component, args, &error); if (!o) { g_task_return_error (task, g_steal_pointer (&error)); return; diff --git a/lib/wp/component-loader.h b/lib/wp/component-loader.h index 3c6267eb..7ff44387 100644 --- a/lib/wp/component-loader.h +++ b/lib/wp/component-loader.h @@ -10,6 +10,7 @@ #define __WIREPLUMBER_COMPONENT_LOADER_H__ #include "plugin.h" +#include "spa-json.h" G_BEGIN_DECLS @@ -29,7 +30,7 @@ struct _WpComponentLoaderClass gboolean (*supports_type) (WpComponentLoader * self, const gchar * type); void (*load) (WpComponentLoader * self, const gchar * component, - const gchar * type, GVariant * args, GAsyncReadyCallback callback, + const gchar * type, WpSpaJson * args, GAsyncReadyCallback callback, gpointer data); /*< private >*/ diff --git a/lib/wp/core.h b/lib/wp/core.h index d62b51ba..6b1e6fca 100644 --- a/lib/wp/core.h +++ b/lib/wp/core.h @@ -12,6 +12,7 @@ #include #include "defs.h" #include "properties.h" +#include "spa-json.h" G_BEGIN_DECLS @@ -49,7 +50,7 @@ gchar *wp_core_get_vm_type (WpCore *self); WP_API 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); WP_API diff --git a/modules/module-default-nodes-api.c b/modules/module-default-nodes-api.c index eca4850a..f7e7fc4b 100644 --- a/modules/module-default-nodes-api.c +++ b/modules/module-default-nodes-api.c @@ -307,7 +307,7 @@ wp_default_nodes_api_class_init (WpDefaultNodesApiClass * klass) } 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 (), "name", "default-nodes-api", diff --git a/modules/module-file-monitor-api.c b/modules/module-file-monitor-api.c index 34d0677d..991bb44a 100644 --- a/modules/module-file-monitor-api.c +++ b/modules/module-file-monitor-api.c @@ -204,7 +204,7 @@ wp_file_monitor_api_class_init (WpFileMonitorApiClass * klass) } 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 (), "name", "file-monitor-api", diff --git a/modules/module-logind.c b/modules/module-logind.c index 26b64f99..43952536 100644 --- a/modules/module-logind.c +++ b/modules/module-logind.c @@ -134,7 +134,7 @@ wp_logind_class_init (WpLogindClass * klass) } 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 (), "name", NAME, diff --git a/modules/module-lua-scripting/module.c b/modules/module-lua-scripting/module.c index a31a75a9..42faf1fa 100644 --- a/modules/module-lua-scripting/module.c +++ b/modules/module-lua-scripting/module.c @@ -173,7 +173,7 @@ on_script_loaded (WpObject *object, GAsyncResult *res, gpointer data) static void 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) { WpLuaScriptingPlugin * self = WP_LUA_SCRIPTING_PLUGIN (cl); @@ -238,7 +238,7 @@ wp_lua_scripting_plugin_class_init (WpLuaScriptingPluginClass * klass) } 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 (), "name", "lua-scripting", diff --git a/modules/module-lua-scripting/script.c b/modules/module-lua-scripting/script.c index 945eb581..38b32272 100644 --- a/modules/module-lua-scripting/script.c +++ b/modules/module-lua-scripting/script.c @@ -29,7 +29,7 @@ struct _WpLuaScript lua_State *L; gchar *filename; - GVariant *args; + WpSpaJson *args; }; enum { @@ -64,7 +64,7 @@ wp_lua_script_finalize (GObject * object) wp_lua_script_cleanup (self); g_clear_pointer (&self->L, wplua_unref); 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); } @@ -86,7 +86,7 @@ wp_lua_script_set_property (GObject * object, guint property_id, self->filename = g_value_dup_string (value); break; case PROP_ARGUMENTS: - self->args = g_value_dup_variant (value); + self->args = g_value_dup_boxed (value); break; default: 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 */ 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++; } @@ -282,7 +282,7 @@ wp_lua_script_class_init (WpLuaScriptClass * klass) G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_ARGUMENTS, - g_param_spec_variant ("arguments", "arguments", "arguments", - G_VARIANT_TYPE_VARDICT, NULL, + g_param_spec_boxed ("arguments", "arguments", "arguments", + WP_TYPE_SPA_JSON, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); } diff --git a/modules/module-lua-scripting/wplua/boxed.c b/modules/module-lua-scripting/wplua/boxed.c index 467e7305..83288319 100644 --- a/modules/module-lua-scripting/wplua/boxed.c +++ b/modules/module-lua-scripting/wplua/boxed.c @@ -30,6 +30,7 @@ _wplua_gboxed___index (lua_State *L) "expected userdata storing GValue"); GValue *obj_v = lua_touserdata (L, 1); const gchar *key = luaL_checkstring (L, 2); + GType type = G_VALUE_TYPE (obj_v); lua_CFunction func = NULL; GHashTable *vtables; @@ -39,15 +40,15 @@ _wplua_gboxed___index (lua_State *L) lua_pop (L, 1); /* search in registered vtables */ - if (!func) { - GType type = G_VALUE_TYPE (obj_v); - while (!func && type) { - luaL_Reg *reg = g_hash_table_lookup (vtables, GUINT_TO_POINTER (type)); - func = find_method_in_luaL_Reg (reg, key); - type = g_type_parent (type); - } + while (!func && type) { + luaL_Reg *reg = g_hash_table_lookup (vtables, GUINT_TO_POINTER (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) { lua_pushcfunction (L, func); return 1; diff --git a/modules/module-mixer-api.c b/modules/module-mixer-api.c index f8e87fdf..3106da34 100644 --- a/modules/module-mixer-api.c +++ b/modules/module-mixer-api.c @@ -617,7 +617,7 @@ wp_mixer_api_class_init (WpMixerApiClass * klass) } 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 (), "name", "mixer-api", diff --git a/modules/module-portal-permissionstore.c b/modules/module-portal-permissionstore.c index 6f5bc26a..7683da25 100644 --- a/modules/module-portal-permissionstore.c +++ b/modules/module-portal-permissionstore.c @@ -305,7 +305,7 @@ wp_portal_permissionstore_plugin_class_init ( } 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_portal_permissionstore_plugin_get_type(), diff --git a/modules/module-reserve-device/plugin.c b/modules/module-reserve-device/plugin.c index 469fe69f..86089536 100644 --- a/modules/module-reserve-device/plugin.c +++ b/modules/module-reserve-device/plugin.c @@ -267,7 +267,7 @@ wp_reserve_device_plugin_class_init (WpReserveDevicePluginClass * klass) } 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 (), "name", "reserve-device", diff --git a/modules/module-settings.c b/modules/module-settings.c index d50920f7..10dbeebf 100644 --- a/modules/module-settings.c +++ b/modules/module-settings.c @@ -339,15 +339,15 @@ wp_settings_plugin_class_init (WpSettingsPluginClass * klass) } 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) - 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 (), "name", "settings", "core", core, - "metadata-name", metadata_name, + "metadata-name", metadata_name ? metadata_name : "sm-settings", NULL)); } diff --git a/modules/module-si-audio-adapter.c b/modules/module-si-audio-adapter.c index fc81c86d..0071b4f7 100644 --- a/modules/module-si-audio-adapter.c +++ b/modules/module-si-audio-adapter.c @@ -780,7 +780,7 @@ si_audio_adapter_linkable_init (WpSiLinkableInterface * iface) } 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, si_audio_adapter_get_type ())); diff --git a/modules/module-si-audio-virtual.c b/modules/module-si-audio-virtual.c index c652369f..00dbced5 100644 --- a/modules/module-si-audio-virtual.c +++ b/modules/module-si-audio-virtual.c @@ -358,7 +358,7 @@ si_audio_virtual_adapter_init (WpSiAdapterInterface * iface) } 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, si_audio_virtual_get_type ())); diff --git a/modules/module-si-node.c b/modules/module-si-node.c index 58fe256c..abadbf79 100644 --- a/modules/module-si-node.c +++ b/modules/module-si-node.c @@ -222,7 +222,7 @@ si_node_linkable_init (WpSiLinkableInterface * iface) } 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, si_node_get_type ())); diff --git a/modules/module-si-standard-link.c b/modules/module-si-standard-link.c index edf7e584..5a39d5e9 100644 --- a/modules/module-si-standard-link.c +++ b/modules/module-si-standard-link.c @@ -778,7 +778,7 @@ si_standard_link_link_init (WpSiLinkInterface * iface) } 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, si_standard_link_get_type ())); diff --git a/modules/module-standard-event-source.c b/modules/module-standard-event-source.c index dd4330dd..7e21e601 100644 --- a/modules/module-standard-event-source.c +++ b/modules/module-standard-event-source.c @@ -452,7 +452,7 @@ wp_standard_event_source_class_init (WpStandardEventSourceClass * klass) } 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 (), "name", "standard-event-source", diff --git a/src/tools/wpexec.c b/src/tools/wpexec.c index 9e78c934..d73d1d34 100644 --- a/src/tools/wpexec.c +++ b/src/tools/wpexec.c @@ -27,8 +27,8 @@ enum WpExitCode }; static gchar * exec_script = NULL; -static GVariantBuilder exec_args_b = - G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_VARDICT); +static gchar *exec_args_s = NULL; +static WpSpaJson *exec_args = NULL; static gboolean 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; } - g_auto(GStrv) tokens = g_strsplit (value, "=", 2); - if (!tokens[0] || *g_strstrip (tokens[0]) == '\0') { - g_set_error (error, WP_DOMAIN_DAEMON, WP_EXIT_USAGE, - "invalid script argument '%s'; must be in key=value format", value); - return FALSE; + /* the second argument is a json object with script arguments */ + if (!exec_args) { + exec_args_s = g_strdup (value); + exec_args = wp_spa_json_new_from_string (exec_args_s); + 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; } @@ -146,8 +147,7 @@ wp_init_transition_execute_step (WpTransition * transition, guint step) } case STEP_ACTIVATE_SCRIPT: { - GVariant *args = g_variant_builder_end (&exec_args_b); - wp_core_load_component (core, exec_script, "script/lua", args, + wp_core_load_component (core, exec_script, "script/lua", exec_args, (GAsyncReadyCallback) on_plugin_loaded, self); break; } diff --git a/tests/examples/interactive.lua b/tests/examples/interactive.lua index 4d2e1dc5..96a4115c 100755 --- a/tests/examples/interactive.lua +++ b/tests/examples/interactive.lua @@ -10,21 +10,23 @@ -- This is an example of an interactive script -- -- Execute with: --- wpexec ./interactive.lua option1=value1 option2=value2 ... +-- wpexec ./interactive.lua '{ option1 = "value1" , option2 = "value2" }' ... -- or: --- ./interactive.lua option1=value1 option2=value2 +-- ./interactive.lua '{ option1 = "value1" , option2 = "value2" }' ----------------------------------------------------------------------------- -- -- Collects arguments passed in from the command line --- Assuming option1=value1 option2=value2 were passed, this will be a table --- like this: { ["option1"] = "value1", ["option2"] = "value2" } +-- Assuming '{ option1 = "value1" , option2 = "value2" }' were passed, +-- this will be a table like this: +-- { ["option1"] = "value1", ["option2"] = "value2" } -- local argv = ... +if argv then + argv = argv:parse() -print ("Command-line arguments:") -for k, v in pairs(argv) do - print ("\t" .. k .. ": " .. v) + print ("Command-line arguments:") + Debug.dump_table (argv) end --