42 #define AST_DB_FAMILY "MediaCache"
45 #define AST_DB_FAMILY_LEN 12
48 #define AO2_BUCKETS 61
57 if (ast_strlen_zero(uri)) {
81 static int metadata_sync_to_astdb(
void *obj,
void *arg,
int flags)
84 const char *hash = arg;
96 static void media_cache_item_sync_to_astdb(
struct ast_bucket_file *bucket_file)
114 static void media_cache_item_del_from_astdb(
struct ast_bucket_file *bucket_file)
124 ast_free(hash_value);
133 static void bucket_file_update_path(
struct ast_bucket_file *bucket_file,
134 const char *preferred_file_name)
136 if (!ast_strlen_zero(preferred_file_name) && strcmp(bucket_file->
path, preferred_file_name)) {
138 rename(bucket_file->
path, preferred_file_name);
140 sizeof(bucket_file->
path));
141 }
else if (!strchr(bucket_file->
path,
'.')) {
148 rename(bucket_file->
path, new_path);
158 char *file_path,
size_t len)
163 if (ast_strlen_zero(uri)) {
167 ao2_lock(media_cache);
168 ast_debug(5,
"Looking for media at local cache, file: %s\n", uri);
179 if ((ext = strrchr(file_path,
'.'))) {
184 ast_debug(5,
"Returning media at local file: %s\n", file_path);
185 ao2_unlock(media_cache);
197 ao2_unlock(media_cache);
204 ast_debug(2,
"Failed to obtain media at '%s'\n", uri);
209 ao2_lock(media_cache);
215 if (tmp_bucket_file) {
219 ao2_unlock(media_cache);
226 bucket_file_update_path(bucket_file, preferred_file_name);
227 media_cache_item_sync_to_astdb(bucket_file);
229 if ((ext = strrchr(file_path,
'.'))) {
235 ast_debug(5,
"Returning media at local file: %s\n", file_path);
236 ao2_unlock(media_cache);
242 char *value,
size_t len)
247 if (ast_strlen_zero(uri) || ast_strlen_zero(key) || !value) {
280 if (ast_strlen_zero(file_path) || ast_strlen_zero(uri)) {
285 if (stat(file_path, &st)) {
286 ast_log(LOG_WARNING,
"Unable to obtain information for file %s for URI %s\n",
309 ast_log(LOG_WARNING,
"Failed to create file storage for %s and %s\n",
316 strcpy(bucket_file->
path, file_path);
317 bucket_file->
created.tv_sec = st.st_ctime;
318 bucket_file->
modified.tv_sec = st.st_mtime;
320 snprintf(tmp,
sizeof(tmp),
"%ld", (
long)st.st_atime);
323 snprintf(tmp,
sizeof(tmp),
"%jd", (intmax_t)st.st_size);
326 ext = strrchr(file_path_ptr,
'.');
331 for (it_metadata = metadata; it_metadata; it_metadata = it_metadata->
next) {
336 ast_log(LOG_WARNING,
"Failed to create media for %s\n", uri);
340 media_cache_item_sync_to_astdb(bucket_file);
352 if (ast_strlen_zero(uri)) {
362 media_cache_item_del_from_astdb(bucket_file);
375 static void media_cache_remove_from_astdb(
const char *uri,
const char *hash)
389 static int media_cache_item_populate_from_astdb(
const char *uri,
const char *hash)
402 for (db_entry = db_tree; db_entry; db_entry = db_entry->next) {
403 const char *key = strchr(db_entry->key + 1,
'/');
405 if (ast_strlen_zero(key)) {
410 if (!strcasecmp(key,
"path")) {
411 strcpy(bucket_file->path, db_entry->data);
413 if (stat(bucket_file->path, &st)) {
414 ast_log(LOG_WARNING,
"Unable to obtain information for file %s for URI %s\n",
415 bucket_file->path, uri);
426 if (ast_strlen_zero(bucket_file->path)) {
428 ast_log(LOG_WARNING,
"Failed to restore media cache item for '%s' from AstDB: no 'path' specified\n",
443 static void media_cache_populate_from_astdb(
void)
449 for (db_entry = db_tree; db_entry; db_entry = db_entry->next) {
450 if (media_cache_item_populate_from_astdb(db_entry->key +
AST_DB_FAMILY_LEN, db_entry->data)) {
451 media_cache_remove_from_astdb(db_entry->key, db_entry->data);
461 static int media_cache_prnt_summary(
void *obj,
void *arg,
int flags)
463 #define FORMAT_ROW "%-40s\n\t%-40s\n"
477 e->
command =
"media cache show all";
479 "Usage: media cache show all\n"
480 " Display a summary of all current items in the media cache.\n";
487 return CLI_SHOWUSAGE;
490 ast_cli(a->fd,
"URI\n\tLocal File\n");
491 ast_cli(a->fd,
"---------------\n");
501 static char *cli_complete_uri(
const char *word)
505 int wordlen = strlen(word);
508 while ((bucket_file = ao2_iterator_next(&it_media_items))) {
521 #define FORMAT_ROW "\t%20s: %-40.40s\n"
528 e->
command =
"media cache show";
530 "Usage: media cache show <uri>\n"
531 " Display all information about a particular item in the media cache.\n";
534 return a->pos == e->
args ? cli_complete_uri(a->word) : NULL;
538 return CLI_SHOWUSAGE;
543 ast_cli(a->fd,
"Unable to find '%s' in the media cache\n", a->argv[3]);
548 ast_cli(a->fd,
"%s\n",
"----------------------------------------");
549 ast_cli(a->fd, FORMAT_ROW,
"Path", bucket_file->
path);
552 while ((metadata = ao2_iterator_next(&it_metadata))) {
553 ast_cli(a->fd, FORMAT_ROW, metadata->
name, metadata->
value);
567 e->
command =
"media cache delete";
569 "Usage: media cache delete <uri>\n"
570 " Delete an item from the media cache.\n\n"
571 " Note that this will also remove any local storage of the media associated\n"
572 " with the URI, and will inform the backend supporting the URI scheme that\n"
573 " it should remove the item.\n";
576 return a->pos == e->
args ? cli_complete_uri(a->word) : NULL;
580 return CLI_SHOWUSAGE;
584 ast_cli(a->fd,
"Unable to delete '%s'\n", a->argv[3]);
586 ast_cli(a->fd,
"Deleted '%s' from the media cache\n", a->argv[3]);
594 char file_path[PATH_MAX];
598 e->
command =
"media cache refresh";
600 "Usage: media cache refresh <uri>\n"
601 " Ask for a refresh of a particular URI.\n\n"
602 " If the item does not already exist in the media cache, the item will be\n"
603 " populated from the backend supporting the URI scheme.\n";
606 return a->pos == e->
args ? cli_complete_uri(a->word) : NULL;
610 return CLI_SHOWUSAGE;
614 ast_cli(a->fd,
"Unable to refresh '%s'\n", a->argv[3]);
616 ast_cli(a->fd,
"Refreshed '%s' to local storage '%s'\n", a->argv[3], file_path);
626 e->
command =
"media cache create";
628 "Usage: media cache create <uri> <file>\n"
629 " Create an item in the media cache by associating a local media file with\n"
637 return CLI_SHOWUSAGE;
641 ast_cli(a->fd,
"Unable to create '%s' associated with local file '%s'\n",
642 a->argv[3], a->argv[4]);
644 ast_cli(a->fd,
"Created '%s' for '%s' in the media cache\n",
645 a->argv[3], a->argv[4]);
652 AST_CLI_DEFINE(media_cache_handle_show_all,
"Show all items in the media cache"),
653 AST_CLI_DEFINE(media_cache_handle_show_item,
"Show a single item in the media cache"),
654 AST_CLI_DEFINE(media_cache_handle_delete_item,
"Remove an item from the media cache"),
655 AST_CLI_DEFINE(media_cache_handle_refresh_item,
"Refresh an item in the media cache"),
656 AST_CLI_DEFINE(media_cache_handle_create_item,
"Create an item in the media cache"),
663 static void media_cache_shutdown(
void)
665 ao2_cleanup(media_cache);
685 media_cache_populate_from_astdb();
struct ast_bucket_metadata * ast_bucket_file_metadata_get(struct ast_bucket_file *file, const char *name)
Retrieve a metadata attribute from a file.
struct ast_variable * next
Asterisk main include file. File version handling, generic pbx functions.
int ast_bucket_file_metadata_set(struct ast_bucket_file *file, const char *name, const char *value)
Set a metadata attribute on a file to a specific value.
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
The arg parameter is a search key, but is not an object.
descriptor for a cli entry.
int ast_file_is_readable(const char *filename)
Test that a file exists and is readable by the effective user.
void ast_db_freetree(struct ast_db_entry *entry)
Free structure created by ast_db_gettree()
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container, as described below.
struct ast_bucket_file * ast_bucket_file_retrieve(const char *uri)
Retrieve a bucket file.
Structure for variables, used for configurations and for channel variables.
int ast_sorcery_object_id_compare(void *obj, void *arg, int flags)
ao2 object comparator based on sorcery id.
Assume that the ao2_container is already locked.
int ast_db_get_allocated(const char *family, const char *key, char **out)
Get key value specified by family/key as a heap allocated string.
#define ast_cli_register_multiple(e, len)
Register multiple commands.
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ao2_link_flags(container, obj, flags)
Add an object to a container.
#define ast_strdup(str)
A wrapper for strdup()
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
struct ast_bucket_file * ast_bucket_file_alloc(const char *uri)
Allocate a new bucket file.
struct timeval modified
When this file was last modified.
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
int args
This gets set in ast_cli_register()
Configuration File Parser.
struct timeval created
When this file was created.
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
#define ast_strdupa(s)
duplicate a string in memory from the stack
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
struct ast_bucket_file * ast_bucket_file_clone(struct ast_bucket_file *file)
Clone a bucket file.
int ast_bucket_file_delete(struct ast_bucket_file *file)
Delete a bucket file from backend storage.
int ast_bucket_file_is_stale(struct ast_bucket_file *file)
Retrieve whether or not the backing datastore views the bucket file as stale.
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
void ast_bucket_file_metadata_callback(struct ast_bucket_file *file, ao2_callback_fn cb, void *arg)
Execute a callback function on the metadata associated with a file.
#define ast_debug(level,...)
Log a DEBUG message.
Bucket file structure, contains reference to file and information about it.
void ast_sha1_hash(char *output, const char *input)
Produces SHA1 hash based on input string.
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
struct ast_db_entry * ast_db_gettree(const char *family, const char *keytree)
Get a list of values within the astdb tree.
struct ao2_container * metadata
Container of metadata attributes about file.
#define SCOPED_AO2LOCK(varname, obj)
scoped lock specialization for ao2 mutexes.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Standard Command Line Interface.
int ast_db_del(const char *family, const char *key)
Delete entry in astdb.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
int ast_sorcery_object_id_hash(const void *obj, int flags)
ao2 object hasher based on sorcery id.
#define ao2_unlink_flags(container, obj, flags)
Remove an object from a container.
int ast_db_put(const char *family, const char *key, const char *value)
Store value addressed by family/key.
int ast_cli_completion_add(char *value)
Add a result to a request for completion options.
Persistent data storage (akin to *doze registry)
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
char path[PATH_MAX]
Local path to this file.
int ast_bucket_file_create(struct ast_bucket_file *file)
Create a new bucket file in backend storage.
int ast_db_deltree(const char *family, const char *keytree)
Delete one or more entries in astdb.
#define ao2_link(container, obj)
Add an object to a container.