lua: api: bind json-utils functions

This commit is contained in:
George Kiagiadakis 2023-11-07 11:08:18 +02:00
parent 89ac416e99
commit fbecc50319
4 changed files with 236 additions and 0 deletions

View file

@ -1713,6 +1713,86 @@ static const luaL_Reg conf_methods[] = {
{ NULL, NULL }
};
/* JsonUtils */
static gboolean
json_utils_match_rules_cb (gpointer data, const gchar * action,
WpSpaJson * value, GError ** error)
{
lua_State *L = data;
g_autoptr (GError) pcall_err = NULL;
gboolean ret = TRUE;
int top = lua_gettop (L);
/* this callback is called within the context of json_utils_match_rules()
* and the Lua callback function is at the top of the stack at this point */
/* re-push the function because lua_call pops it; then, push arguments */
lua_pushvalue (L, -1);
lua_pushstring (L, action);
wplua_pushboxed (L, WP_TYPE_SPA_JSON, wp_spa_json_ref (value));
lua_call (L, 2, 2);
ret = lua_toboolean (L, -2);
if (!ret) {
g_set_error (error, WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_OPERATION_FAILED,
"%s", lua_tostring (L, -1));
}
lua_settop (L, top);
return ret;
}
static int
json_utils_match_rules (lua_State *L)
{
g_autoptr (WpProperties) properties = NULL;
g_autoptr (GError) error = NULL;
WpSpaJson *json;
gboolean res;
json = wplua_checkboxed (L, 1, WP_TYPE_SPA_JSON);
luaL_checktype (L, 2, LUA_TTABLE);
luaL_checktype (L, 3, LUA_TFUNCTION);
properties = wplua_table_to_properties (L, 2);
res = wp_json_utils_match_rules (json, properties, json_utils_match_rules_cb,
L, &error);
lua_pushboolean (L, res);
if (error)
lua_pushstring (L, error->message);
else
lua_pushnil (L);
return 2;
}
static int
json_utils_match_rules_update_properties (lua_State *L)
{
g_autoptr (WpProperties) properties = NULL;
WpSpaJson *json;
int count;
json = wplua_checkboxed (L, 1, WP_TYPE_SPA_JSON);
luaL_checktype (L, 2, LUA_TTABLE);
properties = wplua_table_to_properties (L, 2);
count = wp_json_utils_match_rules_update_properties (json, properties);
lua_pushinteger (L, count);
wplua_properties_to_table (L, properties);
return 2;
}
static const luaL_Reg json_utils_funcs[] = {
{ "match_rules", json_utils_match_rules },
{ "match_rules_update_properties", json_utils_match_rules_update_properties },
{ NULL, NULL }
};
/* WpSettings */
static int
@ -2390,6 +2470,9 @@ wp_lua_scripting_api_init (lua_State *L)
luaL_newlib (L, conf_methods);
lua_setglobal (L, "WpConf");
luaL_newlib (L, json_utils_funcs);
lua_setglobal (L, "JsonUtils");
luaL_newlib (L, settings_methods);
lua_setglobal (L, "WpSettings");

View file

@ -212,6 +212,7 @@ SANDBOX_EXPORT = {
ImplMetadata = WpImplMetadata_new,
Settings = WpSettings,
Conf = WpConf,
JsonUtils = JsonUtils,
SimpleEventHook = WpSimpleEventHook_new,
AsyncEventHook = WpAsyncEventHook_new,
}

View file

@ -30,6 +30,12 @@ test(
args: ['lua-api-tests', 'json.lua'],
env: common_env,
)
test(
'test-lua-json-utils',
script_tester,
args: ['lua-api-tests', 'json-utils.lua'],
env: common_env,
)
test(
'test-lua-monitor-rules',
script_tester,

View file

@ -0,0 +1,146 @@
rules_json_str = [[
[
{
matches = [
{
device.name = "~alsa_card.*"
}
]
actions = {
update-props = {
api.alsa.use-acp = true
api.acp.auto-port = false
}
}
}
{
matches = [
{
node.name = "alsa_output.0.my-alsa-device"
}
]
actions = {
update-props = {
audio.rate = 96000
node.description = "My ALSA Node"
media.class = null
}
}
}
]
]]
match_props = { ["device.name"] = "unmatched-device-name" }
ret, ret_props = JsonUtils.match_rules_update_properties (Json.Raw (rules_json_str), match_props)
assert (ret == 0)
assert (ret_props["device.name"] == match_props["device.name"])
match_props = { ["device.name"] = "alsa_card_0.my-alsa-device" }
ret, ret_props = JsonUtils.match_rules_update_properties (Json.Raw (rules_json_str), match_props)
assert (ret == 2)
assert (ret_props["device.name"] == "alsa_card_0.my-alsa-device")
assert (ret_props["api.alsa.use-acp"] == "true")
assert (ret_props["api.acp.auto-port"] == "false")
match_props = { ["node.name"] = "alsa_output.0.my-alsa-device" }
ret, ret_props = JsonUtils.match_rules_update_properties (Json.Raw (rules_json_str), match_props)
assert (ret == 2)
assert (ret_props["node.name"] == "alsa_output.0.my-alsa-device")
assert (ret_props["audio.rate"] == "96000")
assert (ret_props["node.description"] == "My ALSA Node")
assert (ret_props["media.class"] == nil)
match_props = {
["node.name"] = "alsa_output.0.my-alsa-device",
["media.class"] = "Audio/Sink",
["audio.rate"] = "48000",
["node.description"] = "Test",
}
ret, ret_props = JsonUtils.match_rules_update_properties (Json.Raw (rules_json_str), match_props)
assert (ret == 3)
assert (ret_props["node.name"] == "alsa_output.0.my-alsa-device")
assert (ret_props["audio.rate"] == "96000")
assert (ret_props["node.description"] == "My ALSA Node")
assert (ret_props["media.class"] == nil)
rules_json_str = [[
[
{
matches = [
{
device.name = "~alsa_card.*"
}
]
actions = {
update-props = {
api.acp.auto-port = false
}
set-answer = 42
}
}
{
matches = [
{
test.error = true
}
]
actions = {
generate-error = "test.error is true"
}
}
{
matches = [
{
device.name = "alsa_card.1"
}
]
actions = {
set-description = "My ALSA Device"
}
}
]
]]
function match_rules_callback (action, value)
if action == "update-props" then
local updates = value:parse ()
for k,v in pairs (updates) do
match_props[k] = tostring (v)
end
elseif action == "set-answer" then
local v = value:parse ()
match_props["answer.universe"] = tostring (v)
elseif action == "generate-error" then
local err = value:parse ()
return false, tostring (err)
elseif action == "set-description" then
local str = value:parse ()
match_props["device.description"] = tostring (str)
end
return true
end
match_props = {
["device.name"] = "alsa_card.1",
["test.error"] = "false",
}
ret, err = JsonUtils.match_rules (Json.Raw (rules_json_str), match_props, match_rules_callback)
assert (ret == true)
assert (err == nil)
assert (match_props["device.name"] == "alsa_card.1")
assert (match_props["api.acp.auto-port"] == "false")
assert (match_props["answer.universe"] == "42")
assert (match_props["device.description"] == "My ALSA Device")
match_props = {
["device.name"] = "alsa_card.1",
["test.error"] = "true",
}
ret, err = JsonUtils.match_rules (Json.Raw (rules_json_str), match_props, match_rules_callback)
assert (ret == false)
assert (err == "test.error is true")
assert (match_props["device.name"] == "alsa_card.1")
assert (match_props["api.acp.auto-port"] == "false")
assert (match_props["answer.universe"] == "42")
assert (match_props["device.description"] == nil)