From a0b7a49a4a238207a2fe0a49fdc3b65994baa1a5 Mon Sep 17 00:00:00 2001 From: Kinsey Moore Date: Mon, 24 Jun 2013 13:49:20 +0000 Subject: Index installed sounds and implement ARI sounds queries This adds support for stasis/sounds and stasis/sounds/{ID} queries via the Asterisk RESTful Interface (ARI, formerly Stasis-HTTP). The following changes have been made to accomplish this: * A modular indexer was created for local media. * A new function to get an ast_format associated with a file extension was added. * Modifications were made to the built-in HTTP server so that URI decoding could be deferred to the URI handler when necessary. * The Stasis-HTTP sounds JSON documentation was modified to handle cases where multiple languages are installed in different formats. * Register and Unregister events for formats were added to the system topic. (closes issue ASTERISK-21584) (closes issue ASTERISK-21585) Review: https://reviewboard.asterisk.org/r/2507/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@392700 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- res/res_stasis_http.c | 4 +- res/stasis_http/resource_sounds.c | 185 +++++++++++++++++++++++++++++++++++++- 2 files changed, 186 insertions(+), 3 deletions(-) (limited to 'res') diff --git a/res/res_stasis_http.c b/res/res_stasis_http.c index a4ea30567..09ab9dc1d 100644 --- a/res/res_stasis_http.c +++ b/res/res_stasis_http.c @@ -506,7 +506,7 @@ void stasis_http_invoke(const char *uri, struct stasis_rest_handlers *handler; struct ast_variable *path_vars = NULL; char *path = ast_strdupa(uri); - const char *path_segment; + char *path_segment; stasis_rest_callback callback; root = handler = get_root_handler(); @@ -515,6 +515,7 @@ void stasis_http_invoke(const char *uri, while ((path_segment = strsep(&path, "/")) && (strlen(path_segment) > 0)) { struct stasis_rest_handlers *found_handler = NULL; int i; + ast_uri_decode(path_segment, ast_uri_http_legacy); ast_debug(3, "Finding handler for %s\n", path_segment); for (i = 0; found_handler == NULL && i < handler->num_children; ++i) { struct stasis_rest_handlers *child = handler->children[i]; @@ -863,6 +864,7 @@ static struct ast_http_uri http_uri = { .has_subtree = 1, .data = NULL, .key = __FILE__, + .no_decode_uri = 1, }; static int load_module(void) diff --git a/res/stasis_http/resource_sounds.c b/res/stasis_http/resource_sounds.c index a1808a159..235ce9d93 100644 --- a/res/stasis_http/resource_sounds.c +++ b/res/stasis_http/resource_sounds.c @@ -28,12 +28,193 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "resource_sounds.h" +#include "asterisk/media_index.h" +#include "asterisk/sounds_index.h" +#include "asterisk/format.h" +#include "asterisk/format_cap.h" +#include "asterisk/json.h" + +/*! \brief arguments that are necessary for adding format/lang pairs */ +struct lang_format_info { + struct ast_json *format_list; /*!< The embedded array to which format/lang pairs should be added */ + const char *filename; /*!< Name of the file for which to add format/lang pairs */ + const char *format_filter; /*!< Format filter provided in the request */ +}; + +/*! \brief Add format/lang pairs to the array embedded in the sound object */ +static int add_format_information_cb(void *obj, void *arg, int flags) +{ + char *language = obj; + struct lang_format_info *args = arg; + struct ast_format format; + RAII_VAR(struct ast_format_cap *, cap, NULL, ast_format_cap_destroy); + RAII_VAR(struct ast_media_index *, sounds_index, ast_sounds_get_index(), ao2_cleanup); + + if (!sounds_index) { + return CMP_STOP; + } + + cap = ast_media_get_format_cap(sounds_index, args->filename, language); + if (!cap) { + return CMP_STOP; + } + + ast_format_cap_iter_start(cap); + while (!ast_format_cap_iter_next(cap, &format)) { + struct ast_json *lang_format_pair; + const char *format_name = ast_getformatname(&format); + + if (!ast_strlen_zero(args->format_filter) + && strcmp(args->format_filter, format_name)) { + continue; + } + + lang_format_pair = ast_json_pack("{s: s, s: s}", + "language", language, + "format", format_name); + if (!lang_format_pair) { + ast_format_cap_iter_end(cap); + return CMP_STOP; + } + + ast_json_array_append(args->format_list, lang_format_pair); + } + ast_format_cap_iter_end(cap); + return 0; +} + +/*! \brief Filter out all languages not matching the specified language */ +static int filter_langs_cb(void *obj, void *arg, int flags) +{ + char *lang_filter = arg; + char *lang = obj; + if (strcmp(lang, lang_filter)) { + return CMP_MATCH; + } + return 0; +} + +/*! \brief Generate a Sound structure as documented in sounds.json for the specified filename */ +static struct ast_json *create_sound_blob(const char *filename, struct ast_get_sounds_args *args) +{ + RAII_VAR(struct ast_json *, sound, NULL, ast_json_unref); + RAII_VAR(struct ao2_container *, languages, NULL, ao2_cleanup); + const char *description; + struct ast_json *format_lang_list; + struct lang_format_info info; + RAII_VAR(struct ast_media_index *, sounds_index, ast_sounds_get_index(), ao2_cleanup); + + if (!sounds_index) { + return NULL; + } + + description = ast_media_get_description(sounds_index, filename, "en"); + if (ast_strlen_zero(description)) { + sound = ast_json_pack("{s: s, s: []}", + "id", filename, + "formats"); + } else { + sound = ast_json_pack("{s: s, s: s, s: []}", + "id", filename, + "text", description, + "formats"); + } + if (!sound) { + return NULL; + } + + format_lang_list = ast_json_object_get(sound, "formats"); + if (!format_lang_list) { + return NULL; + } + + languages = ast_media_get_variants(sounds_index, filename); + if (!languages || !ao2_container_count(languages)) { + return NULL; + } + + /* filter requested languages */ + if (args && !ast_strlen_zero(args->lang)) { + char *lang_filter = ast_strdupa(args->lang); + ao2_callback(languages, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, filter_langs_cb, lang_filter); + if (!languages || !ao2_container_count(languages)) { + return NULL; + } + } + + info.filename = filename; + info.format_list = format_lang_list; + info.format_filter = NULL; + if (args) { + info.format_filter = args->format; + } + ao2_callback(languages, OBJ_NODATA, add_format_information_cb, &info); + + /* no format/lang pairs for this sound so nothing to return */ + if (!ast_json_array_size(format_lang_list)) { + return NULL; + } + + return ast_json_ref(sound); +} + +/*! \brief Generate a Sound structure and append it to the output blob */ +static int append_sound_cb(void *obj, void *arg, void *data, int flags) +{ + struct ast_json *sounds_array = arg; + char *filename = obj; + struct ast_get_sounds_args *args = data; + struct ast_json *sound_blob = create_sound_blob(filename, args); + if (!sound_blob) { + return 0; + } + + ast_json_array_append(sounds_array, sound_blob); + return 0; +} void stasis_http_get_sounds(struct ast_variable *headers, struct ast_get_sounds_args *args, struct stasis_http_response *response) { - ast_log(LOG_ERROR, "TODO: stasis_http_get_sounds\n"); + RAII_VAR(struct ao2_container *, sound_files, NULL, ao2_cleanup); + struct ast_json *sounds_blob; + RAII_VAR(struct ast_media_index *, sounds_index, ast_sounds_get_index(), ao2_cleanup); + + if (!sounds_index) { + stasis_http_response_error(response, 500, "Internal Error", "Sounds index not available"); + return; + } + + sound_files = ast_media_get_media(sounds_index); + if (!sound_files) { + stasis_http_response_error(response, 500, "Internal Error", "Allocation Error"); + return; + } + + sounds_blob = ast_json_array_create(); + if (!sounds_blob) { + stasis_http_response_error(response, 500, "Internal Error", "Allocation Error"); + return; + } + + ao2_callback_data(sound_files, OBJ_NODATA, append_sound_cb, sounds_blob, args); + + if (!ast_json_array_size(sounds_blob)) { + stasis_http_response_error(response, 404, "Not Found", "No sounds found that matched the query"); + return; + } + + stasis_http_response_ok(response, sounds_blob); } + void stasis_http_get_stored_sound(struct ast_variable *headers, struct ast_get_stored_sound_args *args, struct stasis_http_response *response) { - ast_log(LOG_ERROR, "TODO: stasis_http_get_stored_sound\n"); + struct ast_json *sound_blob; + + sound_blob = create_sound_blob(args->sound_id, NULL); + if (!sound_blob) { + stasis_http_response_error(response, 404, "Not Found", "Sound not found"); + return; + } + + stasis_http_response_ok(response, sound_blob); } -- cgit v1.2.3