mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-30 02:26:23 +00:00
loader: Use ast_cli_completion_add for 'module load' completion.
This addresses all performance issues with 'module load' completion. In addition to using ast_cli_completion_add we stop using libedit's filename_completion_function, instead using ast_file_read_dir. This ensures all results are produced from a single call to opendir. Change-Id: I8bf51ffaa7ef1606f3bd1b5bb13f1905d72c6134
This commit is contained in:
@@ -143,6 +143,11 @@ int ast_filecopy(const char *oldname, const char *newname, const char *fmt);
|
|||||||
* \param filename the name of the file
|
* \param filename the name of the file
|
||||||
* \param obj user data object
|
* \param obj user data object
|
||||||
* \return non-zero to stop reading, otherwise zero to continue
|
* \return non-zero to stop reading, otherwise zero to continue
|
||||||
|
*
|
||||||
|
* \note dir_name is not processed by realpath or other functions,
|
||||||
|
* symbolic links are not resolved. This ensures dir_name
|
||||||
|
* always starts with the exact string originally passed to
|
||||||
|
* \ref ast_file_read_dir or \ref ast_file_read_dirs.
|
||||||
*/
|
*/
|
||||||
typedef int (*ast_file_on_file)(const char *dir_name, const char *filename, void *obj);
|
typedef int (*ast_file_on_file)(const char *dir_name, const char *filename, void *obj);
|
||||||
|
|
||||||
|
@@ -154,7 +154,6 @@ endif
|
|||||||
|
|
||||||
db.o: _ASTCFLAGS+=$(SQLITE3_INCLUDE)
|
db.o: _ASTCFLAGS+=$(SQLITE3_INCLUDE)
|
||||||
asterisk.o: _ASTCFLAGS+=$(LIBEDIT_INCLUDE)
|
asterisk.o: _ASTCFLAGS+=$(LIBEDIT_INCLUDE)
|
||||||
loader.o: _ASTCFLAGS+=$(LIBEDIT_INCLUDE)
|
|
||||||
json.o: _ASTCFLAGS+=$(JANSSON_INCLUDE)
|
json.o: _ASTCFLAGS+=$(JANSSON_INCLUDE)
|
||||||
bucket.o: _ASTCFLAGS+=$(URIPARSER_INCLUDE)
|
bucket.o: _ASTCFLAGS+=$(URIPARSER_INCLUDE)
|
||||||
crypt.o: _ASTCFLAGS+=$(CRYPT_INCLUDE)
|
crypt.o: _ASTCFLAGS+=$(CRYPT_INCLUDE)
|
||||||
|
@@ -36,7 +36,6 @@
|
|||||||
#include "asterisk/_private.h"
|
#include "asterisk/_private.h"
|
||||||
#include "asterisk/paths.h" /* use ast_config_AST_MODULE_DIR */
|
#include "asterisk/paths.h" /* use ast_config_AST_MODULE_DIR */
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <editline/readline.h>
|
|
||||||
|
|
||||||
#include "asterisk/dlinkedlists.h"
|
#include "asterisk/dlinkedlists.h"
|
||||||
#include "asterisk/module.h"
|
#include "asterisk/module.h"
|
||||||
@@ -56,6 +55,7 @@
|
|||||||
#include "asterisk/app.h"
|
#include "asterisk/app.h"
|
||||||
#include "asterisk/test.h"
|
#include "asterisk/test.h"
|
||||||
#include "asterisk/sounds_index.h"
|
#include "asterisk/sounds_index.h"
|
||||||
|
#include "asterisk/cli.h"
|
||||||
|
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
|
||||||
@@ -1036,57 +1036,55 @@ static int module_matches_helper_type(struct ast_module *mod, enum ast_module_he
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *module_load_helper(const char *word, int state)
|
struct module_load_word {
|
||||||
{
|
const char *word;
|
||||||
struct ast_module *mod;
|
size_t len;
|
||||||
int which = 0;
|
size_t moddir_len;
|
||||||
char *name;
|
};
|
||||||
char *ret = NULL;
|
|
||||||
char *editline_ret;
|
|
||||||
char fullpath[PATH_MAX];
|
|
||||||
int idx = 0;
|
|
||||||
/* This is needed to avoid listing modules that are already running. */
|
|
||||||
AST_VECTOR(, char *) running_modules;
|
|
||||||
|
|
||||||
AST_VECTOR_INIT(&running_modules, 200);
|
static int module_load_helper_on_file(const char *dir_name, const char *filename, void *obj)
|
||||||
|
{
|
||||||
|
struct module_load_word *word = obj;
|
||||||
|
struct ast_module *mod;
|
||||||
|
char *filename_merged = NULL;
|
||||||
|
|
||||||
|
/* dir_name will never be shorter than word->moddir_len. */
|
||||||
|
dir_name += word->moddir_len;
|
||||||
|
if (!ast_strlen_zero(dir_name)) {
|
||||||
|
ast_assert(dir_name[0] == '/');
|
||||||
|
|
||||||
|
dir_name += 1;
|
||||||
|
if (ast_asprintf(&filename_merged, "%s/%s", dir_name, filename) < 0) {
|
||||||
|
/* If we can't allocate the string just give up! */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
filename = filename_merged;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strncasecmp(filename, word->word, word->len)) {
|
||||||
|
/* Don't list files that are already loaded! */
|
||||||
|
mod = find_resource(filename, 0);
|
||||||
|
if (!mod || !mod->flags.running) {
|
||||||
|
ast_cli_completion_add(ast_strdup(filename));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ast_free(filename_merged);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void module_load_helper(const char *word)
|
||||||
|
{
|
||||||
|
struct module_load_word word_l = {
|
||||||
|
.word = word,
|
||||||
|
.len = strlen(word),
|
||||||
|
.moddir_len = strlen(ast_config_AST_MODULE_DIR),
|
||||||
|
};
|
||||||
|
|
||||||
AST_DLLIST_LOCK(&module_list);
|
AST_DLLIST_LOCK(&module_list);
|
||||||
AST_DLLIST_TRAVERSE(&module_list, mod, entry) {
|
ast_file_read_dirs(ast_config_AST_MODULE_DIR, module_load_helper_on_file, &word_l, -1);
|
||||||
if (mod->flags.running) {
|
|
||||||
AST_VECTOR_APPEND(&running_modules, mod->resource);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (word[0] == '/') {
|
|
||||||
/* BUGBUG: we should not support this. */
|
|
||||||
ast_copy_string(fullpath, word, sizeof(fullpath));
|
|
||||||
} else {
|
|
||||||
snprintf(fullpath, sizeof(fullpath), "%s/%s", ast_config_AST_MODULE_DIR, word);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is ugly that we keep calling filename_completion_function.
|
|
||||||
* The only way to avoid this would be to make a copy of the function
|
|
||||||
* that skips matches found in the running_modules vector.
|
|
||||||
*/
|
|
||||||
while (!ret && (name = editline_ret = filename_completion_function(fullpath, idx++))) {
|
|
||||||
if (word[0] != '/') {
|
|
||||||
name += (strlen(ast_config_AST_MODULE_DIR) + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Don't list files that are already loaded! */
|
|
||||||
if (!AST_VECTOR_GET_CMP(&running_modules, name, !strcasecmp) && ++which > state) {
|
|
||||||
ret = ast_strdup(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
ast_std_free(editline_ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Do not clean-up the elements, they belong to module_list. */
|
|
||||||
AST_VECTOR_FREE(&running_modules);
|
|
||||||
AST_DLLIST_UNLOCK(&module_list);
|
AST_DLLIST_UNLOCK(&module_list);
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, enum ast_module_helper_type type)
|
char *ast_module_helper(const char *line, const char *word, int pos, int state, int rpos, enum ast_module_helper_type type)
|
||||||
@@ -1101,7 +1099,9 @@ char *ast_module_helper(const char *line, const char *word, int pos, int state,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (type == AST_MODULE_HELPER_LOAD) {
|
if (type == AST_MODULE_HELPER_LOAD) {
|
||||||
return module_load_helper(word, state);
|
module_load_helper(word);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == AST_MODULE_HELPER_RELOAD) {
|
if (type == AST_MODULE_HELPER_RELOAD) {
|
||||||
|
Reference in New Issue
Block a user