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
This commit is contained in:
George Kiagiadakis
2022-02-21 10:30:56 +02:00
parent 2f186c10e7
commit 17a257ddbe
24 changed files with 18 additions and 15 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,212 @@
-- WirePlumber
--
-- This file contains the API that is made available to the Lua scripts
--
-- Copyright © 2020 Collabora Ltd.
-- @author George Kiagiadakis <george.kiagiadakis@collabora.com>
--
-- SPDX-License-Identifier: MIT
local function Constraint (spec)
assert (type(spec[1]) == "string", "Constraint: expected subject as string");
assert (type(spec[2]) == "string", "Constraint: expected verb as string");
local subject = spec[1]
local verb = spec[2]
local verbs = {
["="] = "equals",
["!"] = "not-equals",
["c"] = "in-list",
["~"] = "in-range",
["#"] = "matches",
["+"] = "is-present",
["-"] = "is-absent"
}
-- check and convert verb to its short version
local verb_is_valid = false
for k, v in pairs(verbs) do
if verb == k or verb == v then
verb = k
spec[2] = k
verb_is_valid = true
break
end
end
assert (verb_is_valid, "Constraint: invalid verb '" .. verb .. "'")
-- check and convert type to its integer value
local type = spec["type"]
if type then
local valid_types = { "pw-global", "pw", "gobject" }
local type_is_valid = false
for i, v in ipairs(valid_types) do
if type == v then
spec["type"] = i
type_is_valid = true
break
end
end
assert(type_is_valid, "Constraint: invalid subject type '" .. type .. "'")
end
-- check if we got the right amount of values
if verb == "=" or verb == "!" or verb == "#" then
assert (spec[3] ~= nil,
"Constraint: " .. verbs[verb] .. ": expected constraint value")
elseif verb == "c" then
assert (spec[3] ~= nil,
"Constraint: " .. verbs[verb] .. ": expected at least one constraint value")
elseif verb == "~" then
assert (spec[3] ~= nil and spec[4] ~= nil,
"Constraint: " .. verbs[verb] .. ": expected two values")
else
assert (spec[3] == nil,
"Constraint: " .. verbs[verb] .. ": expected no value, but there is one")
end
return debug.setmetatable(spec, { __name = "Constraint" })
end
local function dump_table(t, indent)
local indent_str = ""
indent = indent or 1
for i = 1, indent, 1 do
indent_str = indent_str .. "\t"
end
local kvpairs = {}
for k, v in pairs(t) do
table.insert(kvpairs, { k, v })
end
table.sort(kvpairs, function (lhs, rhs)
local left_key, right_key = lhs[1], rhs[1]
-- If the types are different, we sort by the type
-- in alphabetical order. This means that numbers
-- come before before strings, etc
if type(left_key) ~= type(right_key) then
return type(left_key) < type(right_key)
end
local key_type = type(left_key)
-- Only numbers and strings have a well-defined order
-- that's guaranteed to fulfill the requirements of
-- table.sort (strict weak order)
if key_type == "number" or key_type == "string" then
return left_key < right_key
end
-- At this point, we have no good way to order the objects.
-- We can't just do `left_key < right_key`, because this may fail
-- if there's no `__lt` metamethod, and even if there is one,
-- it might not be a strict weak order. (The Lua reference does
-- not say what happens if the order is not strict weak, so it's
-- undefined behaviour)
-- That said, it's always mathematically "permitted" to return `false`,
-- in which case, since both x < y and y < x are false, the elements
-- are considered "equivalent" and may appear in any order in relation
-- to each other. The elements are still sorted in relation to the
-- *other* keys.
return false
-- To be a strict weak order, if x and y are equivalent, and y and z
-- are equivalent, then x and z must be equivalent too. Otherwise the
-- ordering is only a strict *partial* order.
-- Note that the Lua 5.3 reference states that the order merely has to
-- be a strict *partial* order, but since all weak orders are partial
-- orders, this is not a problem.
end)
for _, pair in ipairs(kvpairs) do
local k, v = table.unpack(pair)
if (type(v) == "table") then
print (indent_str .. tostring(k) .. ": ")
dump_table(v, indent + 1)
else
print (indent_str .. tostring(k) .. ": " .. tostring(v))
end
end
end
local Debug = {
dump_table = dump_table,
}
local Id = {
INVALID = 0xffffffff,
ANY = 0xffffffff,
}
local Features = {
PipewireObject = {
MINIMAL = 0x11,
},
ALL = 0xffffffff,
}
local Feature = {
Proxy = {
BOUND = 1,
},
PipewireObject = {
INFO = (1 << 4),
PARAM_PROPS = (1 << 5),
PARAM_FORMAT = (1 << 6),
PARAM_PROFILE = (1 << 7),
PARAM_PORT_CONFIG = (1 << 8),
PARAM_ROUTE = (1 << 9),
},
SpaDevice = {
ENABLED = (1 << 16),
},
Node = {
PORTS = (1 << 16),
},
Session = {
ENDPOINTS = (1 << 16),
LINKS = (1 << 17),
},
Endpoint = {
STREAMS = (1 << 16),
},
Metadata = {
DATA = (1 << 16),
},
SessionItem = {
ACTIVE = (1 << 0),
EXPORTED = (1 << 1),
},
}
SANDBOX_EXPORT = {
Debug = Debug,
Id = Id,
Features = Features,
Feature = Feature,
GLib = GLib,
Log = WpLog,
Core = WpCore,
Plugin = WpPlugin,
ObjectManager = WpObjectManager_new,
Interest = WpObjectInterest_new,
SessionItem = WpSessionItem_new,
Constraint = Constraint,
Device = WpDevice_new,
SpaDevice = WpSpaDevice_new,
Node = WpNode_new,
LocalNode = WpImplNode_new,
Link = WpLink_new,
Pod = WpSpaPod,
Json = WpSpaJson,
State = WpState_new,
LocalModule = WpImplModule_new,
ImplMetadata = WpImplMetadata_new,
}

View File

@@ -0,0 +1,165 @@
/* WirePlumber
*
* Copyright © 2020 Collabora Ltd.
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
#include <wp/wp.h>
#include <wplua/wplua.h>
static gboolean
load_components (lua_State *L, WpCore * core, GError ** error)
{
lua_getglobal (L, "SANDBOX_COMMON_ENV");
switch (lua_getfield (L, -1, "components")) {
case LUA_TTABLE:
break;
case LUA_TNIL:
wp_debug ("no components specified");
goto done;
default:
g_set_error (error, WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_INVALID_ARGUMENT,
"Expected 'components' to be a table");
return FALSE;
}
lua_pushnil (L);
while (lua_next (L, -2)) {
/* value must be a table */
if (lua_type (L, -1) != LUA_TTABLE) {
g_set_error (error, WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_INVALID_ARGUMENT,
"'components' must be a table with tables as values");
return FALSE;
}
/* record indexes to the current key and value of the components table */
int key = lua_absindex (L, -2);
int table = lua_absindex (L, -1);
/* get component */
if (lua_geti (L, table, 1) != LUA_TSTRING) {
g_set_error (error, WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_INVALID_ARGUMENT,
"components['%s'] has a non-string or unspecified component name",
lua_tostring (L, key));
return FALSE;
}
const char * component = lua_tostring (L, -1);
/* get component type */
if (lua_getfield (L, table, "type") != LUA_TSTRING) {
g_set_error (error, WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_INVALID_ARGUMENT,
"components['%s'] has a non-string or unspecified component type",
lua_tostring (L, key));
return FALSE;
}
const char * type = lua_tostring (L, -1);
/* optional component arguments */
GVariant *args = NULL;
if (lua_getfield (L, table, "args") == LUA_TTABLE) {
args = wplua_lua_to_gvariant (L, -1);
}
gboolean optional = FALSE;
if (lua_getfield (L, table, "optional") == LUA_TBOOLEAN) {
optional = lua_toboolean (L, -1);
}
wp_debug ("load component: %s (%s) optional(%s)",
component, type, (optional ? "true" : "false"));
g_autoptr (GError) load_error = NULL;
if (!wp_core_load_component (core, component, type, args, &load_error)) {
if (!optional) {
g_propagate_error (error, g_steal_pointer (&load_error));
return FALSE;
} else {
wp_message ("%s", load_error->message);
}
}
/* clear the stack up to the key */
lua_settop (L, key);
}
done:
lua_pop (L, 2); /* pop components & SANDBOX_COMMON_ENV */
return TRUE;
}
static gboolean
load_file (const GValue *item, GValue *ret, gpointer data)
{
lua_State *L = data;
const gchar *path = g_value_get_string (item);
g_autoptr (GError) error = NULL;
if (g_file_test (path, G_FILE_TEST_IS_DIR))
return TRUE;
wp_info ("loading config file: %s", path);
if (!wplua_load_path (L, path, 0, 0, &error)) {
g_value_unset (ret);
g_value_init (ret, G_TYPE_ERROR);
g_value_take_boxed (ret, g_steal_pointer (&error));
return FALSE;
}
g_value_set_int (ret, g_value_get_int (ret) + 1);
return TRUE;
}
#define CONFIG_DIRS_LOOKUP_SET \
(WP_LOOKUP_DIR_ENV_CONFIG | \
WP_LOOKUP_DIR_XDG_CONFIG_HOME | \
WP_LOOKUP_DIR_ETC | \
WP_LOOKUP_DIR_PREFIX_SHARE)
gboolean
wp_lua_scripting_load_configuration (const gchar * conf_file,
WpCore * core, GError ** error)
{
g_autoptr (lua_State) L = wplua_new ();
g_autofree gchar * path = NULL;
g_autoptr (WpIterator) it = NULL;
g_auto (GValue) fold_ret = G_VALUE_INIT;
gint nfiles = 0;
wplua_enable_sandbox (L, WP_LUA_SANDBOX_MINIMAL_STD);
/* load conf_file itself */
path = wp_find_file (CONFIG_DIRS_LOOKUP_SET, conf_file, NULL);
if (path) {
wp_info ("loading config file: %s", path);
if (!wplua_load_path (L, path, 0, 0, error))
return FALSE;
nfiles = 1;
}
g_clear_pointer (&path, g_free);
path = g_strdup_printf ("%s.d", conf_file);
it = wp_new_files_iterator (CONFIG_DIRS_LOOKUP_SET, path, ".lua");
g_value_init (&fold_ret, G_TYPE_INT);
g_value_set_int (&fold_ret, nfiles);
if (!wp_iterator_fold (it, load_file, &fold_ret, L)) {
if (error && G_VALUE_HOLDS (&fold_ret, G_TYPE_ERROR))
*error = g_value_dup_boxed (&fold_ret);
return FALSE;
}
nfiles = g_value_get_int (&fold_ret);
if (nfiles == 0) {
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
"Could not locate configuration file '%s'", conf_file);
return FALSE;
}
if (!load_components (L, core, error))
return FALSE;
return TRUE;
}

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/org/freedesktop/pipewire/wireplumber/m-lua-scripting/">
<file compressed="true">api.lua</file>
</gresource>
</gresources>

View File

@@ -0,0 +1,345 @@
/* WirePlumber
*
* Copyright © 2022 Collabora Ltd.
* @author Julian Bouzas <julian.bouzas@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
#include <wp/wp.h>
#include <wplua/wplua.h>
/* API */
static int
spa_json_get_data (lua_State *L)
{
WpSpaJson *json = wplua_checkboxed (L, 1, WP_TYPE_SPA_JSON);
lua_pushstring (L, wp_spa_json_get_data (json));
return 1;
}
static int
spa_json_get_size (lua_State *L)
{
WpSpaJson *json = wplua_checkboxed (L, 1, WP_TYPE_SPA_JSON);
lua_pushinteger (L, wp_spa_json_get_size (json));
return 1;
}
static int
spa_json_is_null (lua_State *L)
{
WpSpaJson *json = wplua_checkboxed (L, 1, WP_TYPE_SPA_JSON);
lua_pushboolean (L, wp_spa_json_is_null (json));
return 1;
}
static int
spa_json_is_boolean (lua_State *L)
{
WpSpaJson *json = wplua_checkboxed (L, 1, WP_TYPE_SPA_JSON);
lua_pushboolean (L, wp_spa_json_is_boolean (json));
return 1;
}
static int
spa_json_is_int (lua_State *L)
{
WpSpaJson *json = wplua_checkboxed (L, 1, WP_TYPE_SPA_JSON);
lua_pushboolean (L, wp_spa_json_is_int (json));
return 1;
}
static int
spa_json_is_float (lua_State *L)
{
WpSpaJson *json = wplua_checkboxed (L, 1, WP_TYPE_SPA_JSON);
lua_pushboolean (L, wp_spa_json_is_float (json));
return 1;
}
static int
spa_json_is_string (lua_State *L)
{
WpSpaJson *json = wplua_checkboxed (L, 1, WP_TYPE_SPA_JSON);
lua_pushboolean (L, wp_spa_json_is_string (json));
return 1;
}
static int
spa_json_is_array (lua_State *L)
{
WpSpaJson *json = wplua_checkboxed (L, 1, WP_TYPE_SPA_JSON);
lua_pushboolean (L, wp_spa_json_is_array (json));
return 1;
}
static int
spa_json_is_object (lua_State *L)
{
WpSpaJson *json = wplua_checkboxed (L, 1, WP_TYPE_SPA_JSON);
lua_pushboolean (L, wp_spa_json_is_object (json));
return 1;
}
static void
push_luajson (lua_State *L, WpSpaJson *json)
{
/* Null */
if (wp_spa_json_is_null (json)) {
lua_pushnil (L);
}
/* Boolean */
else if (wp_spa_json_is_boolean (json)) {
gboolean value = FALSE;
g_warn_if_fail (wp_spa_json_parse_boolean (json, &value));
lua_pushboolean (L, value);
}
/* Int */
else if (wp_spa_json_is_int (json)) {
gint value = 0;
g_warn_if_fail (wp_spa_json_parse_int (json, &value));
lua_pushinteger (L, value);
}
/* Float */
else if (wp_spa_json_is_float (json)) {
float value = 0;
g_warn_if_fail (wp_spa_json_parse_float (json, &value));
lua_pushnumber (L, value);
}
/* String */
else if (wp_spa_json_is_string (json)) {
g_autofree gchar *value = wp_spa_json_parse_string (json);
g_warn_if_fail (value);
lua_pushstring (L, value);
}
/* Array */
else if (wp_spa_json_is_array (json)) {
g_auto (GValue) item = G_VALUE_INIT;
g_autoptr (WpIterator) it = wp_spa_json_new_iterator (json);
guint i = 1;
lua_newtable (L);
for (; wp_iterator_next (it, &item); g_value_unset (&item)) {
WpSpaJson *j = g_value_get_boxed (&item);
push_luajson (L, j);
lua_rawseti (L, -2, i++);
}
}
/* Object */
else if (wp_spa_json_is_object (json)) {
g_auto (GValue) item = G_VALUE_INIT;
g_autoptr (WpIterator) it = wp_spa_json_new_iterator (json);
lua_newtable (L);
for (; wp_iterator_next (it, &item); g_value_unset (&item)) {
WpSpaJson *key = g_value_get_boxed (&item);
g_autofree gchar *key_str = NULL;
WpSpaJson *value = NULL;
g_warn_if_fail (wp_spa_json_is_string (key));
key_str = wp_spa_json_parse_string (key);
g_warn_if_fail (key_str);
g_value_unset (&item);
if (!wp_iterator_next (it, &item))
break;
value = g_value_get_boxed (&item);
push_luajson (L, value);
lua_setfield (L, -2, key_str);
}
}
}
static int
spa_json_parse (lua_State *L)
{
WpSpaJson *json = wplua_checkboxed (L, 1, WP_TYPE_SPA_JSON);
push_luajson (L, json);
return 1;
}
/* Raw */
static int
spa_json_raw_new (lua_State *L)
{
const gchar *value = lua_tostring (L, 1);
wplua_pushboxed (L, WP_TYPE_SPA_JSON, wp_spa_json_new_from_string (value));
return 1;
}
/* None */
static int
spa_json_null_new (lua_State *L)
{
wplua_pushboxed (L, WP_TYPE_SPA_JSON, wp_spa_json_new_null ());
return 1;
}
/* Boolean */
static int
spa_json_boolean_new (lua_State *L)
{
gboolean value = lua_toboolean (L, 1);
wplua_pushboxed (L, WP_TYPE_SPA_JSON, wp_spa_json_new_boolean (value));
return 1;
}
/* Int */
static int
spa_json_int_new (lua_State *L)
{
gint64 value = lua_tointeger (L, 1);
wplua_pushboxed (L, WP_TYPE_SPA_JSON, wp_spa_json_new_int (value));
return 1;
}
/* Float */
static int
spa_json_float_new (lua_State *L)
{
float value = lua_tonumber (L, 1);
wplua_pushboxed (L, WP_TYPE_SPA_JSON, wp_spa_json_new_float (value));
return 1;
}
/* String */
static int
spa_json_string_new (lua_State *L)
{
const gchar *value = lua_tostring (L, 1);
wplua_pushboxed (L, WP_TYPE_SPA_JSON, wp_spa_json_new_string (value));
return 1;
}
/* Array */
static int
spa_json_array_new (lua_State *L)
{
g_autoptr (WpSpaJsonBuilder) builder = wp_spa_json_builder_new_array ();
luaL_checktype (L, 1, LUA_TTABLE);
lua_pushnil (L);
while (lua_next (L, 1)) {
switch (lua_type (L, -1)) {
case LUA_TBOOLEAN:
wp_spa_json_builder_add_boolean (builder, lua_toboolean (L, -1));
break;
case LUA_TNUMBER:
if (lua_isinteger (L, -1))
wp_spa_json_builder_add_int (builder, lua_tointeger (L, -1));
else
wp_spa_json_builder_add_float (builder, lua_tonumber (L, -1));
break;
case LUA_TSTRING:
wp_spa_json_builder_add_string (builder, lua_tostring (L, -1));
break;
case LUA_TUSERDATA: {
WpSpaJson *json = wplua_checkboxed (L, -1, WP_TYPE_SPA_JSON);
wp_spa_json_builder_add_json (builder, json);
break;
}
default:
luaL_error (L, "Json does not support lua type ",
lua_typename(L, lua_type(L, -1)));
break;
}
lua_pop (L, 1);
}
wplua_pushboxed (L, WP_TYPE_SPA_JSON, wp_spa_json_builder_end (builder));
return 1;
}
/* Object */
static int
spa_json_object_new (lua_State *L)
{
g_autoptr (WpSpaJsonBuilder) builder = wp_spa_json_builder_new_object ();
luaL_checktype (L, 1, LUA_TTABLE);
lua_pushnil (L);
while (lua_next (L, -2)) {
wp_spa_json_builder_add_property (builder, lua_tostring (L, -2));
switch (lua_type (L, -1)) {
case LUA_TBOOLEAN:
wp_spa_json_builder_add_boolean (builder, lua_toboolean (L, -1));
break;
case LUA_TNUMBER:
if (lua_isinteger (L, -1))
wp_spa_json_builder_add_int (builder, lua_tointeger (L, -1));
else
wp_spa_json_builder_add_float (builder, lua_tonumber (L, -1));
break;
case LUA_TSTRING:
wp_spa_json_builder_add_string (builder, lua_tostring (L, -1));
break;
case LUA_TUSERDATA: {
WpSpaJson *json = wplua_checkboxed (L, -1, WP_TYPE_SPA_JSON);
wp_spa_json_builder_add_json (builder, json);
break;
}
default:
luaL_error (L, "Json does not support lua type ",
lua_typename(L, lua_type(L, -1)));
break;
}
lua_pop (L, 1);
}
wplua_pushboxed (L, WP_TYPE_SPA_JSON, wp_spa_json_builder_end (builder));
return 1;
}
/* Init */
static const luaL_Reg spa_json_methods[] = {
{ "get_data", spa_json_get_data },
{ "get_size", spa_json_get_size },
{ "is_null", spa_json_is_null },
{ "is_boolean", spa_json_is_boolean },
{ "is_int", spa_json_is_int },
{ "is_float", spa_json_is_float },
{ "is_string", spa_json_is_string },
{ "is_array", spa_json_is_array },
{ "is_object", spa_json_is_object },
{ "parse", spa_json_parse },
{ NULL, NULL }
};
static const luaL_Reg spa_json_constructors[] = {
{ "Raw", spa_json_raw_new },
{ "Null", spa_json_null_new },
{ "Boolean", spa_json_boolean_new },
{ "Int", spa_json_int_new },
{ "Float", spa_json_float_new },
{ "String", spa_json_string_new },
{ "Array", spa_json_array_new },
{ "Object", spa_json_object_new },
{ NULL, NULL }
};
void
wp_lua_scripting_json_init (lua_State *L)
{
luaL_newlib (L, spa_json_constructors);
lua_setglobal (L, "WpSpaJson");
wplua_register_type_methods (L, WP_TYPE_SPA_JSON, NULL, spa_json_methods);
}

View File

@@ -0,0 +1,5 @@
m_lua_scripting_resources = gnome.compile_resources(
'm-lua-scripting-resources',
'gresource.xml',
source_dir: meson.current_source_dir(),
c_name: '_m_lua_scripting_resources')

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,201 @@
/* WirePlumber
*
* Copyright © 2021 Collabora Ltd.
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
#include <wp/wp.h>
#include <wplua/wplua.h>
struct _WpRequireApiTransition
{
WpTransition parent;
GPtrArray *apis;
guint pending_plugins;
};
enum {
STEP_LOAD_MODULES = WP_TRANSITION_STEP_CUSTOM_START,
STEP_ACTIVATE_PLUGINS,
};
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_MODULES;
case STEP_LOAD_MODULES: return STEP_ACTIVATE_PLUGINS;
case STEP_ACTIVATE_PLUGINS:
return (self->pending_plugins > 0) ?
STEP_ACTIVATE_PLUGINS : WP_TRANSITION_STEP_NONE;
default:
g_return_val_if_reached (WP_TRANSITION_STEP_ERROR);
}
}
static void
on_plugin_activated (WpObject * p, GAsyncResult * res,
WpRequireApiTransition *self)
{
GError *error = NULL;
if (!wp_object_activate_finish (p, 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_MODULES:
{
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) {
GError *error = NULL;
gchar module_name[50];
g_snprintf (module_name, sizeof (module_name),
"libwireplumber-module-%s", api_name);
if (!wp_core_load_component (core, module_name, "module", NULL, &error)) {
wp_transition_return_error (transition, error);
return;
}
plugin = wp_plugin_find (core, api_name);
if (!plugin) {
wp_transition_return_error (transition, g_error_new (
WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_INVALID_ARGUMENT,
"API '%s' was not found in module '%s'", api_name, module_name));
return;
}
}
}
wp_transition_advance (transition);
break;
}
case STEP_ACTIVATE_PLUGINS:
wp_debug_object (self, "Activating 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);
self->pending_plugins++;
wp_object_activate (WP_OBJECT (plugin), WP_PLUGIN_FEATURE_ENABLED, NULL,
(GAsyncReadyCallback) on_plugin_activated, 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;
}