mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-04 20:04:50 +00:00
sorcery: Add ast_sorcery_retrieve_by_prefix()
Some consumers of the sorcery API use ast_sorcery_retrieve_by_regex only so that they can anchor the potential match as a prefix and not because they truly need regular expressions. Rather than using regular expressions for simple prefix lookups, add a new operation - ast_sorcery_retrieve_by_prefix - that does them. Patches against 13 and 15 have a compatibility layer needed to maintain ABI that is not needed in master. Change-Id: I56f4e20ba1154bd52281f995c27a429a854f6a79
This commit is contained in:
@@ -312,6 +312,14 @@ struct ast_sorcery_wizard {
|
||||
|
||||
/*! \brief Callback for closing a wizard */
|
||||
void (*close)(void *data);
|
||||
|
||||
/*! \brief Optional callback for retrieving multiple objects by matching their id with a prefix */
|
||||
void (*retrieve_prefix)(const struct ast_sorcery *sorcery,
|
||||
void *data,
|
||||
const char *type,
|
||||
struct ao2_container *objects,
|
||||
const char *prefix,
|
||||
const size_t prefix_len);
|
||||
};
|
||||
|
||||
/*! \brief Interface for a sorcery object type observer */
|
||||
@@ -363,10 +371,21 @@ int ast_sorcery_init(void);
|
||||
*/
|
||||
int __ast_sorcery_wizard_register(const struct ast_sorcery_wizard *interface, struct ast_module *module);
|
||||
|
||||
/*!
|
||||
* \brief Register a sorcery wizard
|
||||
*
|
||||
* \param interface Pointer to a wizard interface
|
||||
* \param module Pointer to the module implementing the interface
|
||||
*
|
||||
* \retval 0 success
|
||||
* \retval -1 failure
|
||||
*/
|
||||
int __ast_sorcery_wizard_register_with_prefix(const struct ast_sorcery_wizard *interface, struct ast_module *module);
|
||||
|
||||
/*!
|
||||
* \brief See \ref __ast_sorcery_wizard_register()
|
||||
*/
|
||||
#define ast_sorcery_wizard_register(interface) __ast_sorcery_wizard_register(interface, ast_module_info ? ast_module_info->self : NULL)
|
||||
#define ast_sorcery_wizard_register(interface) __ast_sorcery_wizard_register_with_prefix(interface, ast_module_info ? ast_module_info->self : NULL)
|
||||
|
||||
/*!
|
||||
* \brief Unregister a sorcery wizard
|
||||
@@ -1217,6 +1236,22 @@ void *ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const ch
|
||||
*/
|
||||
struct ao2_container *ast_sorcery_retrieve_by_regex(const struct ast_sorcery *sorcery, const char *type, const char *regex);
|
||||
|
||||
/*!
|
||||
* \brief Retrieve multiple objects whose id begins with the specified prefix
|
||||
* \since 13.19.0
|
||||
*
|
||||
* \param sorcery Pointer to a sorcery structure
|
||||
* \param type Type of object to retrieve
|
||||
* \param prefix Object id prefix
|
||||
* \param prefix_len The length of prefix in bytes
|
||||
*
|
||||
* \retval non-NULL if error occurs
|
||||
* \retval NULL success
|
||||
*
|
||||
* \note The prefix is matched in a case sensitive manner.
|
||||
*/
|
||||
struct ao2_container *ast_sorcery_retrieve_by_prefix(const struct ast_sorcery *sorcery, const char *type, const char *prefix, const size_t prefix_len);
|
||||
|
||||
/*!
|
||||
* \brief Update an object
|
||||
*
|
||||
|
@@ -543,6 +543,27 @@ static void sorcery_internal_wizard_destructor(void *obj)
|
||||
}
|
||||
|
||||
int __ast_sorcery_wizard_register(const struct ast_sorcery_wizard *interface, struct ast_module *module)
|
||||
{
|
||||
struct ast_sorcery_wizard compat = {
|
||||
.name = interface->name,
|
||||
.open = interface->open,
|
||||
.load = interface->load,
|
||||
.reload = interface->reload,
|
||||
.create = interface->create,
|
||||
.retrieve_id = interface->retrieve_id,
|
||||
.retrieve_regex = interface->retrieve_regex,
|
||||
.retrieve_fields = interface->retrieve_fields,
|
||||
.retrieve_multiple = interface->retrieve_multiple,
|
||||
.update = interface->update,
|
||||
.delete = interface->delete,
|
||||
.close = interface->close,
|
||||
.retrieve_prefix = NULL,
|
||||
};
|
||||
|
||||
return __ast_sorcery_wizard_register_with_prefix(&compat, module);
|
||||
}
|
||||
|
||||
int __ast_sorcery_wizard_register_with_prefix(const struct ast_sorcery_wizard *interface, struct ast_module *module)
|
||||
{
|
||||
struct ast_sorcery_internal_wizard *wizard;
|
||||
int res = -1;
|
||||
@@ -1982,6 +2003,36 @@ struct ao2_container *ast_sorcery_retrieve_by_regex(const struct ast_sorcery *so
|
||||
return objects;
|
||||
}
|
||||
|
||||
struct ao2_container *ast_sorcery_retrieve_by_prefix(const struct ast_sorcery *sorcery, const char *type, const char *prefix, const size_t prefix_len)
|
||||
{
|
||||
RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
|
||||
struct ao2_container *objects;
|
||||
int i;
|
||||
|
||||
if (!object_type || !(objects = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
AST_VECTOR_RW_RDLOCK(&object_type->wizards);
|
||||
for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) {
|
||||
struct ast_sorcery_object_wizard *wizard =
|
||||
AST_VECTOR_GET(&object_type->wizards, i);
|
||||
|
||||
if (!wizard->wizard->callbacks.retrieve_prefix) {
|
||||
continue;
|
||||
}
|
||||
|
||||
wizard->wizard->callbacks.retrieve_prefix(sorcery, wizard->data, object_type->name, objects, prefix, prefix_len);
|
||||
|
||||
if (wizard->caching && ao2_container_count(objects)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
AST_VECTOR_RW_UNLOCK(&object_type->wizards);
|
||||
|
||||
return objects;
|
||||
}
|
||||
|
||||
/*! \brief Internal function which returns if the wizard has created the object */
|
||||
static int sorcery_wizard_create(const struct ast_sorcery_object_wizard *object_wizard, const struct sorcery_details *details)
|
||||
{
|
||||
|
@@ -46,6 +46,7 @@ static void *sorcery_astdb_retrieve_fields(const struct ast_sorcery *sorcery, vo
|
||||
static void sorcery_astdb_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects,
|
||||
const struct ast_variable *fields);
|
||||
static void sorcery_astdb_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex);
|
||||
static void sorcery_astdb_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *prefix, const size_t prefix_len);
|
||||
static int sorcery_astdb_update(const struct ast_sorcery *sorcery, void *data, void *object);
|
||||
static int sorcery_astdb_delete(const struct ast_sorcery *sorcery, void *data, void *object);
|
||||
static void sorcery_astdb_close(void *data);
|
||||
@@ -58,6 +59,7 @@ static struct ast_sorcery_wizard astdb_object_wizard = {
|
||||
.retrieve_fields = sorcery_astdb_retrieve_fields,
|
||||
.retrieve_multiple = sorcery_astdb_retrieve_multiple,
|
||||
.retrieve_regex = sorcery_astdb_retrieve_regex,
|
||||
.retrieve_prefix = sorcery_astdb_retrieve_prefix,
|
||||
.update = sorcery_astdb_update,
|
||||
.delete = sorcery_astdb_delete,
|
||||
.close = sorcery_astdb_close,
|
||||
@@ -329,6 +331,42 @@ static void sorcery_astdb_retrieve_regex(const struct ast_sorcery *sorcery, void
|
||||
regfree(&expression);
|
||||
}
|
||||
|
||||
static void sorcery_astdb_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *prefix, const size_t prefix_len)
|
||||
{
|
||||
const char *family_prefix = data;
|
||||
size_t family_len = strlen(family_prefix) + strlen(type) + 1; /* +1 for slash delimiter */
|
||||
char family[family_len + 1];
|
||||
char tree[prefix_len + sizeof("%")];
|
||||
RAII_VAR(struct ast_db_entry *, entries, NULL, ast_db_freetree);
|
||||
struct ast_db_entry *entry;
|
||||
|
||||
snprintf(tree, sizeof(tree), "%.*s%%", (int) prefix_len, prefix);
|
||||
snprintf(family, sizeof(family), "%s/%s", family_prefix, type);
|
||||
|
||||
if (!(entries = ast_db_gettree(family, tree))) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (entry = entries; entry; entry = entry->next) {
|
||||
/* The key in the entry includes the family, so we need to strip it out */
|
||||
const char *key = entry->key + family_len + 2;
|
||||
RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
|
||||
struct ast_json_error error;
|
||||
RAII_VAR(void *, object, NULL, ao2_cleanup);
|
||||
RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
|
||||
|
||||
if (!(json = ast_json_load_string(entry->data, &error))
|
||||
|| (ast_json_to_ast_variables(json, &objset) != AST_JSON_TO_AST_VARS_CODE_SUCCESS)
|
||||
|| !(objset = sorcery_astdb_filter_objectset(objset, sorcery, type))
|
||||
|| !(object = ast_sorcery_alloc(sorcery, type, key))
|
||||
|| ast_sorcery_objectset_apply(sorcery, object, objset)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ao2_link(objects, object);
|
||||
}
|
||||
}
|
||||
|
||||
static int sorcery_astdb_update(const struct ast_sorcery *sorcery, void *data, void *object)
|
||||
{
|
||||
const char *prefix = data;
|
||||
|
@@ -73,6 +73,12 @@ struct sorcery_config_fields_cmp_params {
|
||||
/*! \brief Regular expression for checking object id */
|
||||
regex_t *regex;
|
||||
|
||||
/*! \brief Prefix for matching object id */
|
||||
const char *prefix;
|
||||
|
||||
/*! \brief Prefix length in bytes for matching object id */
|
||||
const size_t prefix_len;
|
||||
|
||||
/*! \brief Optional container to put object into */
|
||||
struct ao2_container *container;
|
||||
};
|
||||
@@ -85,6 +91,7 @@ static void *sorcery_config_retrieve_fields(const struct ast_sorcery *sorcery, v
|
||||
static void sorcery_config_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects,
|
||||
const struct ast_variable *fields);
|
||||
static void sorcery_config_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex);
|
||||
static void sorcery_config_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *prefix, const size_t prefix_len);
|
||||
static void sorcery_config_close(void *data);
|
||||
|
||||
static struct ast_sorcery_wizard config_object_wizard = {
|
||||
@@ -96,6 +103,7 @@ static struct ast_sorcery_wizard config_object_wizard = {
|
||||
.retrieve_fields = sorcery_config_retrieve_fields,
|
||||
.retrieve_multiple = sorcery_config_retrieve_multiple,
|
||||
.retrieve_regex = sorcery_config_retrieve_regex,
|
||||
.retrieve_prefix = sorcery_config_retrieve_prefix,
|
||||
.close = sorcery_config_close,
|
||||
};
|
||||
|
||||
@@ -120,6 +128,11 @@ static int sorcery_config_fields_cmp(void *obj, void *arg, int flags)
|
||||
ao2_link(params->container, obj);
|
||||
}
|
||||
return 0;
|
||||
} else if (params->prefix) {
|
||||
if (!strncmp(params->prefix, ast_sorcery_object_get_id(obj), params->prefix_len)) {
|
||||
ao2_link(params->container, obj);
|
||||
}
|
||||
return 0;
|
||||
} else if (params->fields &&
|
||||
(!(objset = ast_sorcery_objectset_create(params->sorcery, obj)) ||
|
||||
(!ast_variable_lists_match(objset, params->fields, 0)))) {
|
||||
@@ -208,6 +221,24 @@ static void sorcery_config_retrieve_regex(const struct ast_sorcery *sorcery, voi
|
||||
regfree(&expression);
|
||||
}
|
||||
|
||||
static void sorcery_config_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *prefix, const size_t prefix_len)
|
||||
{
|
||||
struct sorcery_config *config = data;
|
||||
RAII_VAR(struct ao2_container *, config_objects, ao2_global_obj_ref(config->objects), ao2_cleanup);
|
||||
struct sorcery_config_fields_cmp_params params = {
|
||||
.sorcery = sorcery,
|
||||
.container = objects,
|
||||
.prefix = prefix,
|
||||
.prefix_len = prefix_len,
|
||||
};
|
||||
|
||||
if (!config_objects) {
|
||||
return;
|
||||
}
|
||||
|
||||
ao2_callback(config_objects, OBJ_NODATA | OBJ_MULTIPLE, sorcery_config_fields_cmp, ¶ms);
|
||||
}
|
||||
|
||||
/*! \brief Internal function which determines if criteria has been met for considering an object set applicable */
|
||||
static int sorcery_is_criteria_met(struct ast_variable *objset, struct ast_variable *criteria)
|
||||
{
|
||||
|
@@ -48,6 +48,7 @@ static void *sorcery_memory_retrieve_fields(const struct ast_sorcery *sorcery, v
|
||||
static void sorcery_memory_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects,
|
||||
const struct ast_variable *fields);
|
||||
static void sorcery_memory_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex);
|
||||
static void sorcery_memory_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *prefix, const size_t prefix_len);
|
||||
static int sorcery_memory_update(const struct ast_sorcery *sorcery, void *data, void *object);
|
||||
static int sorcery_memory_delete(const struct ast_sorcery *sorcery, void *data, void *object);
|
||||
static void sorcery_memory_close(void *data);
|
||||
@@ -60,6 +61,7 @@ static struct ast_sorcery_wizard memory_object_wizard = {
|
||||
.retrieve_fields = sorcery_memory_retrieve_fields,
|
||||
.retrieve_multiple = sorcery_memory_retrieve_multiple,
|
||||
.retrieve_regex = sorcery_memory_retrieve_regex,
|
||||
.retrieve_prefix = sorcery_memory_retrieve_prefix,
|
||||
.update = sorcery_memory_update,
|
||||
.delete = sorcery_memory_delete,
|
||||
.close = sorcery_memory_close,
|
||||
@@ -76,6 +78,12 @@ struct sorcery_memory_fields_cmp_params {
|
||||
/*! \brief Regular expression for checking object id */
|
||||
regex_t *regex;
|
||||
|
||||
/*! \brief Prefix for matching object id */
|
||||
const char *prefix;
|
||||
|
||||
/*! \brief Prefix length in bytes for matching object id */
|
||||
const size_t prefix_len;
|
||||
|
||||
/*! \brief Optional container to put object into */
|
||||
struct ao2_container *container;
|
||||
};
|
||||
@@ -127,6 +135,11 @@ static int sorcery_memory_fields_cmp(void *obj, void *arg, int flags)
|
||||
ao2_link(params->container, obj);
|
||||
}
|
||||
return 0;
|
||||
} else if (params->prefix) {
|
||||
if (!strncmp(params->prefix, ast_sorcery_object_get_id(obj), params->prefix_len)) {
|
||||
ao2_link(params->container, obj);
|
||||
}
|
||||
return 0;
|
||||
} else if (params->fields &&
|
||||
(!(objset = ast_sorcery_objectset_create(params->sorcery, obj)) ||
|
||||
(!ast_variable_lists_match(objset, params->fields, 0)))) {
|
||||
@@ -200,6 +213,18 @@ static void sorcery_memory_retrieve_regex(const struct ast_sorcery *sorcery, voi
|
||||
regfree(&expression);
|
||||
}
|
||||
|
||||
static void sorcery_memory_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *prefix, const size_t prefix_len)
|
||||
{
|
||||
struct sorcery_memory_fields_cmp_params params = {
|
||||
.sorcery = sorcery,
|
||||
.container = objects,
|
||||
.prefix = prefix,
|
||||
.prefix_len = prefix_len,
|
||||
};
|
||||
|
||||
ao2_callback(data, 0, sorcery_memory_fields_cmp, ¶ms);
|
||||
}
|
||||
|
||||
static int sorcery_memory_update(const struct ast_sorcery *sorcery, void *data, void *object)
|
||||
{
|
||||
RAII_VAR(void *, existing, NULL, ao2_cleanup);
|
||||
|
@@ -185,6 +185,10 @@ struct sorcery_memory_cache_fields_cmp_params {
|
||||
const struct ast_variable *fields;
|
||||
/*! \brief Regular expression for checking object id */
|
||||
regex_t *regex;
|
||||
/*! \brief Prefix for matching object id */
|
||||
const char *prefix;
|
||||
/*! \brief Prefix length in bytes for matching object id */
|
||||
const size_t prefix_len;
|
||||
/*! \brief Optional container to put object into */
|
||||
struct ao2_container *container;
|
||||
};
|
||||
@@ -201,6 +205,8 @@ static void sorcery_memory_cache_retrieve_multiple(const struct ast_sorcery *sor
|
||||
struct ao2_container *objects, const struct ast_variable *fields);
|
||||
static void sorcery_memory_cache_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type,
|
||||
struct ao2_container *objects, const char *regex);
|
||||
static void sorcery_memory_cache_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type,
|
||||
struct ao2_container *objects, const char *prefix, const size_t prefix_len);
|
||||
static int sorcery_memory_cache_delete(const struct ast_sorcery *sorcery, void *data, void *object);
|
||||
static void sorcery_memory_cache_close(void *data);
|
||||
|
||||
@@ -216,6 +222,7 @@ static struct ast_sorcery_wizard memory_cache_object_wizard = {
|
||||
.retrieve_fields = sorcery_memory_cache_retrieve_fields,
|
||||
.retrieve_multiple = sorcery_memory_cache_retrieve_multiple,
|
||||
.retrieve_regex = sorcery_memory_cache_retrieve_regex,
|
||||
.retrieve_prefix = sorcery_memory_cache_retrieve_prefix,
|
||||
.close = sorcery_memory_cache_close,
|
||||
};
|
||||
|
||||
@@ -1253,6 +1260,11 @@ static int sorcery_memory_cache_fields_cmp(void *obj, void *arg, int flags)
|
||||
ao2_link(params->container, cached->object);
|
||||
}
|
||||
return 0;
|
||||
} else if (params->prefix) {
|
||||
if (!strncmp(params->prefix, ast_sorcery_object_get_id(cached->object), params->prefix_len)) {
|
||||
ao2_link(params->container, cached->object);
|
||||
}
|
||||
return 0;
|
||||
} else if (params->fields &&
|
||||
(!ast_variable_lists_match(cached->objectset, params->fields, 0))) {
|
||||
/* If we can't turn the object into an object set OR if differences exist between the fields
|
||||
@@ -1376,6 +1388,40 @@ static void sorcery_memory_cache_retrieve_regex(const struct ast_sorcery *sorcer
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Callback function to retrieve multiple objects whose id matches a prefix
|
||||
*
|
||||
* \param sorcery The sorcery instance
|
||||
* \param data The sorcery memory cache
|
||||
* \param type The type of the object to retrieve
|
||||
* \param objects Container to place the objects into
|
||||
* \param prefix Prefix to match against the object id
|
||||
*/
|
||||
static void sorcery_memory_cache_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type,
|
||||
struct ao2_container *objects, const char *prefix, const size_t prefix_len)
|
||||
{
|
||||
struct sorcery_memory_cache *cache = data;
|
||||
struct sorcery_memory_cache_fields_cmp_params params = {
|
||||
.sorcery = sorcery,
|
||||
.cache = cache,
|
||||
.container = objects,
|
||||
.prefix = prefix,
|
||||
.prefix_len = prefix_len,
|
||||
};
|
||||
|
||||
if (is_passthru_update() || !cache->full_backend_cache) {
|
||||
return;
|
||||
}
|
||||
|
||||
memory_cache_full_update(sorcery, type, cache);
|
||||
ao2_callback(cache->objects, 0, sorcery_memory_cache_fields_cmp, ¶ms);
|
||||
|
||||
if (ao2_container_count(objects)) {
|
||||
memory_cache_stale_check(sorcery, cache);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Callback function to finish configuring the memory cache
|
||||
|
@@ -59,6 +59,8 @@ static void *sorcery_realtime_retrieve_fields(const struct ast_sorcery *sorcery,
|
||||
static void sorcery_realtime_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects,
|
||||
const struct ast_variable *fields);
|
||||
static void sorcery_realtime_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex);
|
||||
static void sorcery_realtime_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type,
|
||||
struct ao2_container *objects, const char *prefix, const size_t prefix_len);
|
||||
static int sorcery_realtime_update(const struct ast_sorcery *sorcery, void *data, void *object);
|
||||
static int sorcery_realtime_delete(const struct ast_sorcery *sorcery, void *data, void *object);
|
||||
static void sorcery_realtime_close(void *data);
|
||||
@@ -71,6 +73,7 @@ static struct ast_sorcery_wizard realtime_object_wizard = {
|
||||
.retrieve_fields = sorcery_realtime_retrieve_fields,
|
||||
.retrieve_multiple = sorcery_realtime_retrieve_multiple,
|
||||
.retrieve_regex = sorcery_realtime_retrieve_regex,
|
||||
.retrieve_prefix = sorcery_realtime_retrieve_prefix,
|
||||
.update = sorcery_realtime_update,
|
||||
.delete = sorcery_realtime_delete,
|
||||
.close = sorcery_realtime_close,
|
||||
@@ -262,6 +265,23 @@ static void sorcery_realtime_retrieve_regex(const struct ast_sorcery *sorcery, v
|
||||
sorcery_realtime_retrieve_multiple(sorcery, data, type, objects, fields);
|
||||
}
|
||||
|
||||
static void sorcery_realtime_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type,
|
||||
struct ao2_container *objects, const char *prefix, const size_t prefix_len)
|
||||
{
|
||||
char field[strlen(UUID_FIELD) + 6], value[prefix_len + 2];
|
||||
RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
|
||||
|
||||
if (prefix_len) {
|
||||
snprintf(field, sizeof(field), "%s LIKE", UUID_FIELD);
|
||||
snprintf(value, sizeof(value), "%.*s%%", (int) prefix_len, prefix);
|
||||
if (!(fields = ast_variable_new(field, value, ""))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
sorcery_realtime_retrieve_multiple(sorcery, data, type, objects, fields);
|
||||
}
|
||||
|
||||
static int sorcery_realtime_update(const struct ast_sorcery *sorcery, void *data, void *object)
|
||||
{
|
||||
struct sorcery_config *config = data;
|
||||
|
Reference in New Issue
Block a user