[Asterisk-code-review] main/media cache: Add CLI commands (asterisk[master])

Matt Jordan asteriskteam at digium.com
Tue May 19 20:18:17 CDT 2015


Matt Jordan has uploaded a new change for review.

  https://gerrit.asterisk.org/488

Change subject: main/media_cache: Add CLI commands
......................................................................

main/media_cache: Add CLI commands

This patch adds five CLI commands for the media cache:
 * 'media cache show all' - display a summary of all items in the media
   cache.
 * 'media cache show <uri>' - display detailed information about a
   single item in the media cache.
 * 'media cache delete <uri>' - remove an item from the media cache, and
   inform the bucket backend for the URI scheme to remove the item as
   well.
 * 'media cache refresh <uri>' - refresh a URI. If the item does not
   exist in the media cache, the bucket backend will pull down the media
   associated with the URI and create the item in the cache.
 * 'media cache create <uri>' - create an item in the media cache from
   some local media storage. Note that the bucket backend for the URI
   scheme must still permit the item creation.

Change-Id: Id1c5707a3b8e2d96b56e4691a46a936cd171f4ae
---
M main/media_cache.c
1 file changed, 236 insertions(+), 11 deletions(-)


  git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/88/488/1

diff --git a/main/media_cache.c b/main/media_cache.c
index 6916f15..36393df 100644
--- a/main/media_cache.c
+++ b/main/media_cache.c
@@ -36,6 +36,7 @@
 #include "asterisk/config.h"
 #include "asterisk/bucket.h"
 #include "asterisk/astdb.h"
+#include "asterisk/cli.h"
 #include "asterisk/media_cache.h"
 
 /*! The name of the AstDB family holding items in the cache. */
@@ -213,10 +214,14 @@
 	bucket_file = ao2_find(media_cache, uri, OBJ_SEARCH_KEY | OBJ_NOLOCK);
 	if (bucket_file) {
 		ao2_lock(bucket_file);
+
 		ast_bucket_file_update(bucket_file);
-		bucket_file_update_path(bucket_file, preferred_file_name);
+		if (!ast_strlen_zero(preferred_file_name)) {
+			bucket_file_update_path(bucket_file, preferred_file_name);
+		}
 		ast_copy_string(file_path, bucket_file->path, len);
 		media_cache_item_sync_to_astdb(bucket_file);
+
 		ao2_unlock(bucket_file);
 		ao2_ref(bucket_file, -1);
 		return 0;
@@ -379,16 +384,6 @@
 
 /*!
  * \internal
- * \brief Shutdown the media cache
- */
-static void media_cache_shutdown(void)
-{
-	ao2_ref(media_cache, -1);
-	media_cache = NULL;
-}
-
-/*!
- * \internal
  * \brief Remove a media cache item from the AstDB
  * \param uri The unique URI that represents the item in the cache
  * \param hash The hash key for the item in the AstDB
@@ -438,6 +433,231 @@
 	ast_db_freetree(db_tree);
 }
 
+/*!
+ * \internal
+ * \brief ao2 callback function for \ref media_cache_handle_show_all
+ */
+static int media_cache_prnt_summary(void *obj, void *arg, int flags)
+{
+#define FORMAT_ROW "%-40s\n\t%-40s\n"
+	struct ast_bucket_file *bucket_file = obj;
+	struct ast_cli_args *a = arg;
+
+	ast_cli(a->fd, FORMAT_ROW, ast_sorcery_object_get_id(bucket_file), bucket_file->path);
+
+#undef FORMAT_ROW
+	return CMP_MATCH;
+}
+
+static char *media_cache_handle_show_all(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "media cache show all";
+		e->usage =
+			"Usage: media cache show all\n"
+			"       Display a summary of all current items\n"
+			"       in the media cache.\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+
+	if (a->argc != 4) {
+		return CLI_SHOWUSAGE;
+	}
+
+	ast_cli(a->fd, "URI\n\tLocal File\n");
+	ast_cli(a->fd, "---------------\n");
+	ao2_callback(media_cache, OBJ_NODATA | OBJ_MULTIPLE, media_cache_prnt_summary, a);
+
+	return CLI_SUCCESS;
+}
+
+/*!
+ * \internal
+ * \brief CLI tab completion function for URIs
+ */
+static char *cli_complete_uri(const char *word, int state)
+{
+	struct ast_bucket_file *bucket_file;
+	struct ao2_iterator it_media_items;
+	int wordlen = strlen(word);
+	int which = 0;
+	char *result = NULL;
+
+	it_media_items = ao2_iterator_init(media_cache, 0);
+	while ((bucket_file = ao2_iterator_next(&it_media_items))) {
+		if (!strncasecmp(word, ast_sorcery_object_get_id(bucket_file), wordlen)
+			&& ++which > state) {
+			result = ast_strdup(ast_sorcery_object_get_id(bucket_file));
+		}
+		ao2_ref(bucket_file, -1);
+		if (result) {
+			break;
+		}
+	}
+	ao2_iterator_destroy(&it_media_items);
+	return result;
+}
+
+static char *media_cache_handle_show_item(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+#define FORMAT_ROW "\t%20s: %-40.40s\n"
+	struct ast_bucket_file *bucket_file;
+	struct ao2_iterator it_metadata;
+	struct ast_bucket_metadata *metadata;
+
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "media cache show";
+		e->usage =
+			"Usage: media cache show <uri>\n"
+			"       Display all information about a particular\n"
+			"       item in the media cache.\n";
+		return NULL;
+	case CLI_GENERATE:
+		return cli_complete_uri(a->word, a->n);
+	}
+
+	if (a->argc != 4) {
+		return CLI_SHOWUSAGE;
+	}
+
+	bucket_file = ao2_find(media_cache, a->argv[3], OBJ_SEARCH_KEY);
+	if (!bucket_file) {
+		ast_cli(a->fd, "Unable to find '%s' in the media cache\n", a->argv[3]);
+		return CLI_SUCCESS;
+	}
+
+	ast_cli(a->fd, "URI: %s\n", ast_sorcery_object_get_id(bucket_file));
+	ast_cli(a->fd, "%s\n", "----------------------------------------");
+	ao2_lock(bucket_file);
+	ast_cli(a->fd, FORMAT_ROW, "Path", bucket_file->path);
+
+	it_metadata = ao2_iterator_init(bucket_file->metadata, 0);
+	while ((metadata = ao2_iterator_next(&it_metadata))) {
+		ast_cli(a->fd, FORMAT_ROW, metadata->name, metadata->value);
+		ao2_ref(metadata, -1);
+	}
+	ao2_iterator_destroy(&it_metadata);
+
+	ao2_unlock(bucket_file);
+	ao2_ref(bucket_file, -1);
+#undef FORMAT_ROW
+	return CLI_SUCCESS;
+}
+
+static char *media_cache_handle_delete_item(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "media cache delete";
+		e->usage =
+			"Usage: media cache delete <uri>\n"
+			"       Delete an item from the media cache.\n"
+			"       Note that this will also remove any local\n"
+			"       storage of the media associated with the URI,\n"
+			"       and will inform the backend supporting the URI\n"
+			"       scheme that it should remove the item.\n";
+		return NULL;
+	case CLI_GENERATE:
+		return cli_complete_uri(a->word, a->n);
+	}
+
+	if (a->argc != 4) {
+		return CLI_SHOWUSAGE;
+	}
+
+	if (ast_media_cache_delete(a->argv[3])) {
+		ast_cli(a->fd, "Unable to delete '%s'\n", a->argv[3]);
+	} else {
+		ast_cli(a->fd, "Deleted '%s' from the media cache\n", a->argv[3]);
+	}
+
+	return CLI_SUCCESS;
+}
+
+static char *media_cache_handle_refresh_item(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	char file_path[PATH_MAX];
+
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "media cache refresh";
+		e->usage =
+			"Usage: media cache refresh <uri>\n"
+			"       Ask for a refresh of a particular URI.\n"
+			"       If the item does not already exist in the\n"
+			"       media cache, the item will be populated from\n"
+			"       the backend supporting the URI scheme.\n";
+		return NULL;
+	case CLI_GENERATE:
+		return cli_complete_uri(a->word, a->n);
+	}
+
+	if (a->argc != 4) {
+		return CLI_SHOWUSAGE;
+	}
+
+	if (ast_media_cache_retrieve(a->argv[3], NULL, file_path, sizeof(file_path))) {
+		ast_cli(a->fd, "Unable to refresh '%s'\n", a->argv[3]);
+	} else {
+		ast_cli(a->fd, "Refreshed '%s' to local storage '%s'\n", a->argv[3], file_path);
+	}
+
+	return CLI_SUCCESS;
+}
+
+static char *media_cache_handle_create_item(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "media cache create";
+		e->usage =
+			"Usage: media cache create <uri> <file>\n"
+			"       Create an item in the media cache by associating\n"
+			"       a local media file with some URI.\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+
+	if (a->argc != 5) {
+		return CLI_SHOWUSAGE;
+	}
+
+	if (ast_media_cache_create_or_update(a->argv[3], a->argv[4], NULL)) {
+		ast_cli(a->fd, "Unable to create '%s' associated with local file '%s'\n",
+			a->argv[3], a->argv[4]);
+	} else {
+		ast_cli(a->fd, "Created '%s' for '%s' in the media cache\n",
+			a->argv[3], a->argv[4]);
+	}
+
+	return CLI_SUCCESS;
+}
+
+static struct ast_cli_entry cli_media_cache[] = {
+	AST_CLI_DEFINE(media_cache_handle_show_all, "Show all items in the media cache"),
+	AST_CLI_DEFINE(media_cache_handle_show_item, "Show a single item in the media cache"),
+	AST_CLI_DEFINE(media_cache_handle_delete_item, "Remove an item from the media cache"),
+	AST_CLI_DEFINE(media_cache_handle_refresh_item, "Refresh an item in the media cache"),
+	AST_CLI_DEFINE(media_cache_handle_create_item, "Create an item in the media cache"),
+};
+
+/*!
+ * \internal
+ * \brief Shutdown the media cache
+ */
+static void media_cache_shutdown(void)
+{
+	ao2_ref(media_cache, -1);
+	media_cache = NULL;
+
+	ast_cli_unregister_multiple(cli_media_cache, ARRAY_LEN(cli_media_cache));
+}
+
 int ast_media_cache_init(void)
 {
 	ast_register_atexit(media_cache_shutdown);
@@ -448,6 +668,11 @@
 		return -1;
 	}
 
+	if (ast_cli_register_multiple(cli_media_cache, ARRAY_LEN(cli_media_cache))) {
+		ao2_ref(media_cache, -1);
+		return -1;
+	}
+
 	media_cache_populate_from_astdb();
 
 	return 0;

-- 
To view, visit https://gerrit.asterisk.org/488
To unsubscribe, visit https://gerrit.asterisk.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Id1c5707a3b8e2d96b56e4691a46a936cd171f4ae
Gerrit-PatchSet: 1
Gerrit-Project: asterisk
Gerrit-Branch: master
Gerrit-Owner: Matt Jordan <mjordan at digium.com>



More information about the asterisk-code-review mailing list