summaryrefslogtreecommitdiff
path: root/res
diff options
context:
space:
mode:
authorKinsey Moore <kmoore@digium.com>2013-06-24 13:49:20 +0000
committerKinsey Moore <kmoore@digium.com>2013-06-24 13:49:20 +0000
commita0b7a49a4a238207a2fe0a49fdc3b65994baa1a5 (patch)
tree04bb2ee790a186b6d0865fd9aabc2817a9715f94 /res
parentcc29957a6f3339667f02a7386416c7374122d403 (diff)
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
Diffstat (limited to 'res')
-rw-r--r--res/res_stasis_http.c4
-rw-r--r--res/stasis_http/resource_sounds.c185
2 files changed, 186 insertions, 3 deletions
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);
}