settings: add APIs to parse all types safely

This commit is contained in:
Julian Bouzas
2022-08-27 09:44:17 -04:00
parent a060c6a130
commit a77fe0b021
7 changed files with 361 additions and 3 deletions

View File

@@ -223,6 +223,100 @@ wp_settings_get_all (WpSettings *self, const gchar *pattern)
return wp_spa_json_builder_end (b); return wp_spa_json_builder_end (b);
} }
/*!
* \brief Safely parses a boolean setting, using the fallback value if the
* setting does not exist, or the setting cannot be parsed. A warning is also
* logged when the setting cannot be parsed.
*
* \ingroup wpsettings
* \param self the settings object
* \param setting name of the setting
* \param value fallback value to use in case of error
* \returns The value of the setting, or the fallback value in case of error
*/
gboolean
wp_settings_parse_boolean_safe (WpSettings *self, const gchar *setting,
gboolean value)
{
g_autoptr (WpSpaJson) json = wp_settings_get(self, setting);
gboolean res = value;
if (json && !wp_spa_json_parse_boolean (json, &res))
wp_warning_object (self, "Could not parse setting '%s' as boolean",
setting);
return res;
}
/*!
* \brief Safely parses an integer setting, using the fallback value if the
* setting does not exist, or the setting cannot be parsed. A warning is also
* logged when the setting cannot be parsed.
*
* \ingroup wpsettings
* \param self the settings object
* \param setting name of the setting
* \param value fallback value to use in case of error
* \returns The value of the setting, or the fallback value in case of error
*/
gint
wp_settings_parse_int_safe (WpSettings *self, const gchar *setting, gint value)
{
g_autoptr (WpSpaJson) json = wp_settings_get(self, setting);
gint res = value;
if (json && !wp_spa_json_parse_int (json, &res))
wp_warning_object (self, "Could not parse setting '%s' as int", setting);
return res;
}
/*!
* \brief Safely parses a float setting, using the fallback value if the
* setting does not exist, or the setting cannot be parsed. A warning is also
* logged when the setting cannot be parsed.
*
* \ingroup wpsettings
* \param self the settings object
* \param setting name of the setting
* \param value fallback value to use in case of error
* \returns The value of the setting, or the fallback value in case of error
*/
float
wp_settings_parse_float_safe (WpSettings *self, const gchar *setting,
float value)
{
g_autoptr (WpSpaJson) json = wp_settings_get(self, setting);
float res = value;
if (json && !wp_spa_json_parse_float (json, &res))
wp_warning_object (self, "Could not parse setting '%s' as float", setting);
return res;
}
/*!
* \brief Safely parses a string setting, using the fallback value if the
* setting does not exist, or the setting cannot be parsed. A warning is also
* logged when the setting cannot be parsed.
*
* \ingroup wpsettings
* \param self the settings object
* \param setting name of the setting
* \param value fallback value to use in case of error
* \returns (transfer full): The value of the setting, or the fallback value in
* case of error
*/
gchar *
wp_settings_parse_string_safe (WpSettings *self, const gchar *setting,
const gchar *value)
{
g_autoptr (WpSpaJson) json = wp_settings_get(self, setting);
if (json) {
gchar *res = wp_spa_json_parse_string (json);
if (res)
return res;
else
wp_warning_object (self, "Could not parse setting '%s' as string",
setting);
}
return g_strdup (value);
}
/*! /*!
* \brief Applies the rules and returns the applied properties. * \brief Applies the rules and returns the applied properties.
* *

View File

@@ -67,6 +67,22 @@ WpSpaJson * wp_settings_get (WpSettings *self, const gchar *setting);
WP_API WP_API
WpSpaJson * wp_settings_get_all (WpSettings *self, const gchar *pattern); WpSpaJson * wp_settings_get_all (WpSettings *self, const gchar *pattern);
WP_API
gboolean wp_settings_parse_boolean_safe (WpSettings *self, const gchar *setting,
gboolean value);
WP_API
gint wp_settings_parse_int_safe (WpSettings *self, const gchar *setting,
gint value);
WP_API
float wp_settings_parse_float_safe (WpSettings *self, const gchar *setting,
float value);
WP_API
gchar * wp_settings_parse_string_safe (WpSettings *self, const gchar *setting,
const gchar *value);
WP_API WP_API
gboolean wp_settings_apply_rule (WpSettings *self, const gchar *rule, gboolean wp_settings_apply_rule (WpSettings *self, const gchar *rule,
WpProperties *client_props, WpProperties *applied_props); WpProperties *client_props, WpProperties *applied_props);

View File

@@ -16,6 +16,7 @@
void wp_lua_scripting_pod_init (lua_State *L); void wp_lua_scripting_pod_init (lua_State *L);
void wp_lua_scripting_json_init (lua_State *L); void wp_lua_scripting_json_init (lua_State *L);
void push_luajson (lua_State *L, WpSpaJson *json);
/* helpers */ /* helpers */
@@ -1516,6 +1517,137 @@ settings_get_all (lua_State *L)
return 1; return 1;
} }
static int
settings_parse_boolean_safe (lua_State *L)
{
const char *setting = luaL_checkstring (L, 1);
const gboolean v = lua_toboolean (L, 2) ? TRUE : FALSE;
const char *m = NULL;
g_autoptr (WpSettings) s = NULL;
if (lua_type (L, 3) == LUA_TSTRING)
m = luaL_checkstring (L, 3);
s = wp_settings_get_instance (get_wp_core (L), m);
if (s)
lua_pushboolean (L, wp_settings_parse_boolean_safe (s, setting, v));
else
lua_pushboolean (L, v);
return 1;
}
static int
settings_parse_int_safe (lua_State *L)
{
const char *setting = luaL_checkstring (L, 1);
const gint v = luaL_checkinteger (L, 2);
const char *m = NULL;
g_autoptr (WpSettings) s = NULL;
if (lua_type (L, 3) == LUA_TSTRING)
m = luaL_checkstring (L, 3);
s = wp_settings_get_instance (get_wp_core (L), m);
if (s)
lua_pushinteger (L, wp_settings_parse_int_safe (s, setting, v));
else
lua_pushinteger (L, v);
return 1;
}
static int
settings_parse_float_safe (lua_State *L)
{
const char *setting = luaL_checkstring (L, 1);
const float v = lua_tonumber (L, 2);
const char *m = NULL;
g_autoptr (WpSettings) s = NULL;
if (lua_type (L, 3) == LUA_TSTRING)
m = luaL_checkstring (L, 3);
s = wp_settings_get_instance (get_wp_core (L), m);
if (s)
lua_pushnumber (L, wp_settings_parse_float_safe (s, setting, v));
else
lua_pushnumber (L, v);
return 1;
}
static int
settings_parse_string_safe (lua_State *L)
{
const char *setting = luaL_checkstring (L, 1);
const char *v = luaL_checkstring (L, 2);
const char *m = NULL;
g_autoptr (WpSettings) s = NULL;
g_autofree gchar *res = NULL;
if (lua_type (L, 3) == LUA_TSTRING)
m = luaL_checkstring (L, 3);
s = wp_settings_get_instance (get_wp_core (L), m);
res = s ? wp_settings_parse_string_safe (s, setting, v) : g_strdup (v);
lua_pushstring (L, res);
return 1;
}
static int
settings_parse_array_safe (lua_State *L)
{
const char *setting = luaL_checkstring (L, 1);
const char *m = NULL;
g_autoptr (WpSettings) s = NULL;
g_autoptr (WpSpaJson) json_default = NULL;
if (lua_type (L, 2) == LUA_TSTRING)
m = luaL_checkstring (L, 2);
s = wp_settings_get_instance (get_wp_core (L), m);
if (s) {
g_autoptr (WpSpaJson) j = wp_settings_get (s, setting);
if (j) {
if (wp_spa_json_is_array (j)) {
push_luajson (L, j);
return 1;
} else {
wp_warning ("Ignoring setting '%s' as it isn't a JSON array", setting);
}
}
}
json_default = wp_spa_json_new_array (NULL, NULL);
push_luajson (L, json_default);
return 1;
}
static int
settings_parse_object_safe (lua_State *L)
{
const char *setting = luaL_checkstring (L, 1);
const char *m = NULL;
g_autoptr (WpSettings) s = NULL;
g_autoptr (WpSpaJson) json_default = NULL;
if (lua_type (L, 2) == LUA_TSTRING)
m = luaL_checkstring (L, 2);
s = wp_settings_get_instance (get_wp_core (L), m);
if (s) {
g_autoptr (WpSpaJson) j = wp_settings_get (s, setting);
if (j) {
if (wp_spa_json_is_object (j)) {
push_luajson (L, j);
return 1;
} else {
wp_warning ("Ignoring setting '%s' as it isn't a JSON object", setting);
}
}
}
json_default = wp_spa_json_new_object (NULL, NULL, NULL);
push_luajson (L, json_default);
return 1;
}
static int static int
settings_apply_rule (lua_State *L) settings_apply_rule (lua_State *L)
{ {
@@ -1581,6 +1713,12 @@ settings_unsubscribe (lua_State *L)
static const luaL_Reg settings_methods[] = { static const luaL_Reg settings_methods[] = {
{ "get", settings_get }, { "get", settings_get },
{ "get_all", settings_get_all }, { "get_all", settings_get_all },
{ "parse_boolean_safe", settings_parse_boolean_safe },
{ "parse_int_safe", settings_parse_int_safe },
{ "parse_float_safe", settings_parse_float_safe },
{ "parse_string_safe", settings_parse_string_safe },
{ "parse_array_safe", settings_parse_array_safe },
{ "parse_object_safe", settings_parse_object_safe },
{ "apply_rule", settings_apply_rule }, { "apply_rule", settings_apply_rule },
{ "subscribe", settings_subscribe }, { "subscribe", settings_subscribe },
{ "unsubscribe", settings_unsubscribe }, { "unsubscribe", settings_unsubscribe },

View File

@@ -94,7 +94,7 @@ spa_json_is_object (lua_State *L)
return 1; return 1;
} }
static void void
push_luajson (lua_State *L, WpSpaJson *json) push_luajson (lua_State *L, WpSpaJson *json)
{ {
/* Null */ /* Null */

View File

@@ -124,7 +124,7 @@ test_parsing_setup (TestSettingsFixture *self, gconstpointer user_data)
self->settings = g_steal_pointer (&settings); self->settings = g_steal_pointer (&settings);
/* total no.of settings in the conf file */ /* total no.of settings in the conf file */
g_assert_cmpint (data.count, ==, 12); g_assert_cmpint (data.count, ==, 13);
} }
} }
@@ -141,7 +141,7 @@ static void
test_parsing (TestSettingsFixture *self, gconstpointer data) test_parsing (TestSettingsFixture *self, gconstpointer data)
{ {
/* total no.of settings in the conf file */ /* total no.of settings in the conf file */
g_assert_cmpint (wp_properties_get_count(self->settings), ==, 12); g_assert_cmpint (wp_properties_get_count(self->settings), ==, 13);
} }
static void static void
@@ -280,6 +280,12 @@ test_wpsettings (TestSettingsFixture *self, gconstpointer data)
g_assert_nonnull (j2); g_assert_nonnull (j2);
g_assert_true (wp_spa_json_parse_boolean (j2, &value)); g_assert_true (wp_spa_json_parse_boolean (j2, &value));
g_assert_true (value); g_assert_true (value);
value = wp_settings_parse_boolean_safe (s, "test-setting2", FALSE);
g_assert_true (value);
value = wp_settings_parse_boolean_safe (s, "test-setting-undefined", TRUE);
g_assert_true (value);
} }
{ {
@@ -290,6 +296,12 @@ test_wpsettings (TestSettingsFixture *self, gconstpointer data)
g_assert_nonnull (j); g_assert_nonnull (j);
g_assert_true (wp_spa_json_parse_int (j, &value)); g_assert_true (wp_spa_json_parse_int (j, &value));
g_assert_cmpint (value, ==, -20); g_assert_cmpint (value, ==, -20);
value = wp_settings_parse_int_safe (s, "test-setting3-int", 3);
g_assert_cmpint (value, ==, -20);
value = wp_settings_parse_int_safe (s, "test-setting-undefined", 3);
g_assert_cmpint (value, ==, 3);
} }
{ {
@@ -303,6 +315,20 @@ test_wpsettings (TestSettingsFixture *self, gconstpointer data)
g_assert_cmpstr (value, ==, "blahblah"); g_assert_cmpstr (value, ==, "blahblah");
} }
{
g_autofree gchar *value = NULL;
value = wp_settings_parse_string_safe (s, "test-setting4-string",
"fallback-string");
g_assert_cmpstr (value, ==, "blahblah");
}
{
g_autofree gchar *value = NULL;
value = wp_settings_parse_string_safe (s, "test-setting-undefined",
"fallback-string");
g_assert_cmpstr (value, ==, "fallback-string");
}
{ {
g_autofree gchar *value = NULL; g_autofree gchar *value = NULL;
g_autoptr (WpSpaJson) j = NULL; g_autoptr (WpSpaJson) j = NULL;
@@ -326,6 +352,12 @@ test_wpsettings (TestSettingsFixture *self, gconstpointer data)
g_assert_nonnull (j2); g_assert_nonnull (j2);
g_assert_true (wp_spa_json_parse_float (j2, &value)); g_assert_true (wp_spa_json_parse_float (j2, &value));
g_assert_cmpfloat_with_epsilon (value, 0.4, 0.001); g_assert_cmpfloat_with_epsilon (value, 0.4, 0.001);
value = wp_settings_parse_float_safe (s, "test-setting-float1", 4.14);
g_assert_cmpfloat_with_epsilon (value, 3.14, 0.001);
value = wp_settings_parse_float_safe (s, "test-setting-undefined", 4.14);
g_assert_cmpfloat_with_epsilon (value, 4.14, 0.001);
} }
/* test the wp_settings_get_instance () API */ /* test the wp_settings_get_instance () API */
@@ -391,6 +423,28 @@ test_wpsettings (TestSettingsFixture *self, gconstpointer data)
} }
} }
} }
{
g_autoptr (WpSpaJson) value = NULL;
value = wp_settings_get (s, "test-setting-json3");
g_assert_nonnull (value);
g_assert_true (wp_spa_json_is_object (value));
g_assert_cmpstr (wp_spa_json_get_data(value), ==,
"{ key1: \"value\", key2: 2, key3: true }");
g_autofree gchar *value1 = NULL;
gint value2 = 0;
gboolean value3 = FALSE;
g_assert_true (wp_spa_json_object_get (value,
"key1", "s", &value1,
"key2", "i", &value2,
"key3", "b", &value3,
NULL));
g_assert_cmpstr (value1, ==, "value");
g_assert_cmpint (value2, ==, 2);
g_assert_true (value3);
}
} }
{ {

View File

@@ -166,4 +166,5 @@ wireplumber.settings = {
] ]
test-setting-json = [1, 2, 3] test-setting-json = [1, 2, 3]
test-setting-json2 = ["test1", "test 2", "test three", "test-four"] test-setting-json2 = ["test1", "test 2", "test three", "test-four"]
test-setting-json3 = { key1: "value", key2: 2, key3: true }
} }

View File

@@ -20,12 +20,24 @@ value = Settings.get ("test-setting2", "test-settings"):parse()
assert ("boolean" == type (value)) assert ("boolean" == type (value))
assert (value == true) assert (value == true)
value = Settings.parse_boolean_safe ("test-setting2", false, "test-settings")
assert (value == true)
value = Settings.parse_boolean_safe ("test-setting-undefined", true, "test-settings")
assert (value == true)
-- test settings _get_int () -- test settings _get_int ()
value = Settings.get ("test-setting3-int", "test-settings"):parse() value = Settings.get ("test-setting3-int", "test-settings"):parse()
assert ("number" == type (value)) assert ("number" == type (value))
assert (value == -20) assert (value == -20)
value = Settings.parse_int_safe ("test-setting3-int", 10, "test-settings")
assert (value == -20)
value = Settings.parse_int_safe ("test-setting-undefined", 10, "test-settings")
assert (value == 10)
-- test settings _get_string () -- test settings _get_string ()
value = Settings.get ("test-setting4-string", "test-settings"):parse() value = Settings.get ("test-setting4-string", "test-settings"):parse()
@@ -36,6 +48,12 @@ value = Settings.get ("test-setting5-string-with-quotes", "test-settings"):parse
assert ("string" == type (value)) assert ("string" == type (value))
assert (value == "a string with \"quotes\"") assert (value == "a string with \"quotes\"")
value = Settings.parse_string_safe ("test-setting4-string", "fallback-string", "test-settings")
assert (value == "blahblah")
value = Settings.parse_string_safe ("test-setting-undefined", "fallback-string", "test-settings")
assert (value == "fallback-string")
-- test settings _get_float () -- test settings _get_float ()
value = Settings.get ("test-setting-float1", "test-settings"):parse() value = Settings.get ("test-setting-float1", "test-settings"):parse()
@@ -45,12 +63,28 @@ assert ((value - 3.14) < 0.00001)
value = Settings.get ("test-setting-float2", "test-settings"):parse() value = Settings.get ("test-setting-float2", "test-settings"):parse()
assert ((value - 0.4) < 0.00001) assert ((value - 0.4) < 0.00001)
value = Settings.parse_float_safe ("test-setting-float1", 4.14, "test-settings")
assert ((value - 3.14) < 0.00001)
value = Settings.parse_float_safe ("test-setting-undefined", 4.14, "test-settings")
assert ((value - 4.14) < 0.00001)
-- test settings _get () -- test settings _get ()
value = Settings.get ("test-setting-json", "test-settings") value = Settings.get ("test-setting-json", "test-settings")
assert (value ~= nil) assert (value ~= nil)
assert (value:is_array()) assert (value:is_array())
assert (value:get_data() == "[1, 2, 3]") assert (value:get_data() == "[1, 2, 3]")
value = Settings.parse_array_safe ("test-setting-json", "test-settings")
assert (value ~= nil)
assert (value[1] == 1)
assert (value[2] == 2)
assert (value[3] == 3)
value = Settings.parse_array_safe ("test-setting-undefined", "test-settings")
assert (value ~= nil)
assert (#value == 0)
value = Settings.get ("test-setting-json2", "test-settings") value = Settings.get ("test-setting-json2", "test-settings")
assert (value ~= nil) assert (value ~= nil)
assert (value:is_array()) assert (value:is_array())
@@ -64,6 +98,27 @@ assert (val[4] == "test-four")
assert (val[5] == nil) assert (val[5] == nil)
assert (#val == 4) assert (#val == 4)
value = Settings.get ("test-setting-json3", "test-settings")
assert (value ~= nil)
assert (value:is_object())
print (value:get_data())
assert (value:get_data() ==
"{ key1: \"value\", key2: 2, key3: true }")
val = value:parse ()
assert (val.key1 == "value")
assert (val.key2 == 2)
assert (val.key3 == true)
value = Settings.parse_object_safe ("test-setting-json3", "test-settings")
assert (value ~= nil)
assert (value.key1 == "value")
assert (value.key2 == 2)
assert (value.key3 == true)
value = Settings.parse_object_safe ("test-setting-undefined", "test-settings")
assert (value ~= nil)
assert (#value == 0)
-- test settings _get_all () -- test settings _get_all ()
value = Settings.get_all ("*string*", "test-settings") value = Settings.get_all ("*string*", "test-settings")
assert (value ~= nil) assert (value ~= nil)