#include "asterisk/threadpool.h"
#include "asterisk/json.h"
#include "asterisk/vector.h"
+#include "asterisk/cli.h"
/* To prevent DEBUG_FD_LEAKS from interfering with things we undef open and close */
#undef open
/*! \brief Registered sorcery instances */
static struct ao2_container *instances;
+/* \brief Global config flag (declared in sorcery.h) */
+int ast_sorcery_update_or_create_on_update_miss = 0;
+
static int int_handler_fn(const void *obj, const intptr_t *args, char **buf)
{
int *field = (int *)(obj + args[0]);
AO2_STRING_FIELD_HASH_FN(ast_sorcery_object_field, name)
AO2_STRING_FIELD_CMP_FN(ast_sorcery_object_field, name)
+/*!
+ * \internal
+ * \brief CLI command implementation for 'sorcery show settings'
+ */
+static char *cli_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "sorcery show settings";
+ e->usage = "Usage: sorcery show settings\n"
+ " Show global configuration options\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ }
+
+ ast_cli(a->fd, "\nSorcery global settings\n");
+ ast_cli(a->fd, "-----------------\n");
+ ast_cli(a->fd, " Update->Create fallback in backends: %s\n",
+ ast_sorcery_update_or_create_on_update_miss ? "enabled" : "disabled");
+
+ return CLI_SUCCESS;
+}
+
+
+static struct ast_cli_entry cli_commands[] = {
+ AST_CLI_DEFINE(cli_show_settings, "Show global configuration options"),
+};
+
/*! \brief Cleanup function for graceful shutdowns */
static void sorcery_cleanup(void)
{
+ ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands));
ast_threadpool_shutdown(threadpool);
threadpool = NULL;
ao2_cleanup(wizards);
/*! \brief Hashing function for sorcery instances */
AO2_STRING_FIELD_HASH_FN(sorcery_proxy, module_name)
+/*!
+ * \internal
+ * \brief Parse [general] options from sorcery.conf and set globals.
+ */
+static void parse_general_options(void)
+{
+ struct ast_flags flags = { 0 };
+ struct ast_config *cfg = ast_config_load2("sorcery.conf", "sorcery", flags);
+ const struct ast_variable *var;
+
+ if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
+ return;
+ }
+
+ for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
+ if (!strcasecmp(var->name, "update_or_create_on_update_miss")) {
+ ast_sorcery_update_or_create_on_update_miss = ast_true(var->value);
+ }
+ }
+
+ ast_config_destroy(cfg);
+}
+
int ast_sorcery_init(void)
{
struct ast_threadpool_options options = {
};
ast_assert(wizards == NULL);
+ parse_general_options();
+
threadpool = ast_threadpool_create("sorcery", NULL, &options);
if (!threadpool) {
return -1;
return -1;
}
+ if (ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands))) {
+ return -1;
+ }
+
ast_register_cleanup(sorcery_cleanup);
return 0;
/* If returning multiple objects create a container to store them in */
if ((flags & AST_RETRIEVE_FLAG_MULTIPLE)) {
- object = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, NULL, NULL);
+ object = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT, ast_sorcery_object_id_sort, ast_sorcery_object_id_compare);
if (!object) {
return NULL;
}
return NULL;
}
- objects = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, NULL, NULL);
+ objects = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT, ast_sorcery_object_id_sort, ast_sorcery_object_id_compare);
if (!objects) {
return NULL;
}
return NULL;
}
- objects = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, NULL, NULL);
+ objects = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT, ast_sorcery_object_id_sort, ast_sorcery_object_id_compare);
if (!objects) {
return NULL;
}
{
struct sorcery_config *config = data;
RAII_VAR(struct ast_variable *, fields, ast_sorcery_objectset_create(sorcery, object), ast_variables_destroy);
+ int ret;
+ struct ast_variable *id;
if (!fields) {
return -1;
}
- return (ast_update_realtime_fields(config->family, UUID_FIELD, ast_sorcery_object_get_id(object), fields) < 0) ? -1 : 0;
+ ret = ast_update_realtime_fields(config->family, UUID_FIELD, ast_sorcery_object_get_id(object), fields);
+ if (ret < 0) {
+ /* An error occurred */
+ return -1;
+ } else if (ret > 0) {
+ /* The object was updated */
+ return 0;
+ }
+
+ if (!ast_sorcery_update_or_create_on_update_miss) {
+ /* The object does not exist (nothing was updated) and fallback disabled */
+ return -1;
+ }
+
+ id = ast_variable_new(UUID_FIELD, ast_sorcery_object_get_id(object), "");
+ if (!id) {
+ return -1;
+ }
+
+ /* Place the identifier at the front for sanity sake */
+ id->next = fields;
+ fields = id;
+
+ return (ast_store_realtime_fields(config->family, fields) <= 0) ? -1 : 0;
}
static int sorcery_realtime_delete(const struct ast_sorcery *sorcery, void *data, void *object)