mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-19 03:08:45 +00:00
res_ari: Add support for channel variables in ARI events.
This works the same as for AMI manager variables. Set "channelvars=foo,bar" in your ari.conf general section, and then the channel variables "foo" and "bar" (along with their values), will appear in every Stasis websocket channel event. ASTERISK-26492 #close patches: ari_vars.diff submitted by Mark Michelson Change-Id: I5609ba239259577c0948645df776d7f3bc864229
This commit is contained in:
6
CHANGES
6
CHANGES
@@ -95,6 +95,12 @@ Queue
|
|||||||
* A new dialplan variable, ABANDONED, is set when the call is not answered
|
* A new dialplan variable, ABANDONED, is set when the call is not answered
|
||||||
by an agent.
|
by an agent.
|
||||||
|
|
||||||
|
res_ari
|
||||||
|
------------------
|
||||||
|
* The configuration file ari.conf now supports a channelvars option, which
|
||||||
|
specifies a list of channel variables to include in each channel-oriented
|
||||||
|
ARI event.
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
------------------------------------------------------------------------------
|
||||||
--- Functionality changes from Asterisk 14.0.0 to Asterisk 14.1.0 ----------
|
--- Functionality changes from Asterisk 14.0.0 to Asterisk 14.1.0 ----------
|
||||||
------------------------------------------------------------------------------
|
------------------------------------------------------------------------------
|
||||||
|
@@ -13,6 +13,11 @@ enabled = yes ; When set to no, ARI support is disabled.
|
|||||||
; receiving clients are slow to process the received information. Value is in
|
; receiving clients are slow to process the received information. Value is in
|
||||||
; milliseconds; default is 100 ms.
|
; milliseconds; default is 100 ms.
|
||||||
;websocket_write_timeout = 100
|
;websocket_write_timeout = 100
|
||||||
|
;
|
||||||
|
; Display certain channel variables every time a channel-oriented
|
||||||
|
; event is emitted:
|
||||||
|
;
|
||||||
|
;channelvars = var1,var2,var3
|
||||||
|
|
||||||
;[username]
|
;[username]
|
||||||
;type = user ; Specifies user configuration
|
;type = user ; Specifies user configuration
|
||||||
|
@@ -4339,6 +4339,36 @@ void ast_channel_set_manager_vars(size_t varc, char **vars);
|
|||||||
*/
|
*/
|
||||||
struct varshead *ast_channel_get_manager_vars(struct ast_channel *chan);
|
struct varshead *ast_channel_get_manager_vars(struct ast_channel *chan);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \since 14.2.0
|
||||||
|
* \brief Return whether or not any ARI variables have been set
|
||||||
|
*
|
||||||
|
* \retval 0 if no ARI variables are expected
|
||||||
|
* \retval 1 if ARI variables are expected
|
||||||
|
*/
|
||||||
|
int ast_channel_has_ari_vars(void);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \since 14.2.0
|
||||||
|
* \brief Sets the variables to be stored in the \a ari_vars field of all
|
||||||
|
* snapshots.
|
||||||
|
* \param varc Number of variable names.
|
||||||
|
* \param vars Array of variable names.
|
||||||
|
*/
|
||||||
|
void ast_channel_set_ari_vars(size_t varc, char **vars);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \since 14.2.0
|
||||||
|
* \brief Gets the variables for a given channel, as specified by ast_channel_set_ari_vars().
|
||||||
|
*
|
||||||
|
* The returned variable list is an AO2 object, so ao2_cleanup() to free it.
|
||||||
|
*
|
||||||
|
* \param chan Channel to get variables for.
|
||||||
|
* \return List of channel variables.
|
||||||
|
* \return \c NULL on error
|
||||||
|
*/
|
||||||
|
struct varshead *ast_channel_get_ari_vars(struct ast_channel *chan);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \since 12
|
* \since 12
|
||||||
* \brief Gets the variables for a given channel, as set using pbx_builtin_setvar_helper().
|
* \brief Gets the variables for a given channel, as set using pbx_builtin_setvar_helper().
|
||||||
|
@@ -1076,6 +1076,18 @@ enum ast_json_to_ast_vars_code {
|
|||||||
*/
|
*/
|
||||||
enum ast_json_to_ast_vars_code ast_json_to_ast_variables(struct ast_json *json_variables, struct ast_variable **variables);
|
enum ast_json_to_ast_vars_code ast_json_to_ast_variables(struct ast_json *json_variables, struct ast_variable **variables);
|
||||||
|
|
||||||
|
struct varshead;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Construct a JSON object from a \c ast_var_t list
|
||||||
|
* \since 14.2.0
|
||||||
|
*
|
||||||
|
* \param channelvars The list of \c ast_var_t to represent as JSON
|
||||||
|
*
|
||||||
|
* \return JSON object with variable names as keys and variable values as values
|
||||||
|
*/
|
||||||
|
struct ast_json *ast_json_channel_vars(struct varshead *channelvars);
|
||||||
|
|
||||||
/*!@}*/
|
/*!@}*/
|
||||||
|
|
||||||
#endif /* _ASTERISK_JSON_H */
|
#endif /* _ASTERISK_JSON_H */
|
||||||
|
@@ -73,6 +73,7 @@ struct ast_channel_snapshot {
|
|||||||
struct ast_flags softhangup_flags; /*!< softhangup channel flags */
|
struct ast_flags softhangup_flags; /*!< softhangup channel flags */
|
||||||
struct varshead *manager_vars; /*!< Variables to be appended to manager events */
|
struct varshead *manager_vars; /*!< Variables to be appended to manager events */
|
||||||
int tech_properties; /*!< Properties of the channel's technology */
|
int tech_properties; /*!< Properties of the channel's technology */
|
||||||
|
struct varshead *ari_vars; /*!< Variables to be appended to ARI events */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@@ -7756,35 +7756,48 @@ struct manager_channel_variable {
|
|||||||
char name[];
|
char name[];
|
||||||
};
|
};
|
||||||
|
|
||||||
static AST_RWLIST_HEAD_STATIC(channelvars, manager_channel_variable);
|
AST_RWLIST_HEAD(external_vars, manager_channel_variable);
|
||||||
|
|
||||||
static void free_channelvars(void)
|
static struct external_vars ami_vars;
|
||||||
|
static struct external_vars ari_vars;
|
||||||
|
|
||||||
|
static void free_external_channelvars(struct external_vars *channelvars)
|
||||||
{
|
{
|
||||||
struct manager_channel_variable *var;
|
struct manager_channel_variable *var;
|
||||||
AST_RWLIST_WRLOCK(&channelvars);
|
AST_RWLIST_WRLOCK(channelvars);
|
||||||
while ((var = AST_RWLIST_REMOVE_HEAD(&channelvars, entry))) {
|
while ((var = AST_RWLIST_REMOVE_HEAD(channelvars, entry))) {
|
||||||
ast_free(var);
|
ast_free(var);
|
||||||
}
|
}
|
||||||
AST_RWLIST_UNLOCK(&channelvars);
|
AST_RWLIST_UNLOCK(channelvars);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ast_channel_has_manager_vars(void)
|
static int channel_has_external_vars(struct external_vars *channelvars)
|
||||||
{
|
{
|
||||||
int vars_present;
|
int vars_present;
|
||||||
|
|
||||||
AST_RWLIST_RDLOCK(&channelvars);
|
AST_RWLIST_RDLOCK(channelvars);
|
||||||
vars_present = !AST_LIST_EMPTY(&channelvars);
|
vars_present = !AST_LIST_EMPTY(channelvars);
|
||||||
AST_RWLIST_UNLOCK(&channelvars);
|
AST_RWLIST_UNLOCK(channelvars);
|
||||||
|
|
||||||
return vars_present;
|
return vars_present;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ast_channel_set_manager_vars(size_t varc, char **vars)
|
int ast_channel_has_manager_vars(void)
|
||||||
|
{
|
||||||
|
return channel_has_external_vars(&ami_vars);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ast_channel_has_ari_vars(void)
|
||||||
|
{
|
||||||
|
return channel_has_external_vars(&ari_vars);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void channel_set_external_vars(struct external_vars *channelvars, size_t varc, char **vars)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
free_channelvars();
|
free_external_channelvars(channelvars);
|
||||||
AST_RWLIST_WRLOCK(&channelvars);
|
AST_RWLIST_WRLOCK(channelvars);
|
||||||
for (i = 0; i < varc; ++i) {
|
for (i = 0; i < varc; ++i) {
|
||||||
const char *var = vars[i];
|
const char *var = vars[i];
|
||||||
struct manager_channel_variable *mcv;
|
struct manager_channel_variable *mcv;
|
||||||
@@ -7795,9 +7808,20 @@ void ast_channel_set_manager_vars(size_t varc, char **vars)
|
|||||||
if (strchr(var, '(')) {
|
if (strchr(var, '(')) {
|
||||||
mcv->isfunc = 1;
|
mcv->isfunc = 1;
|
||||||
}
|
}
|
||||||
AST_RWLIST_INSERT_TAIL(&channelvars, mcv, entry);
|
AST_RWLIST_INSERT_TAIL(channelvars, mcv, entry);
|
||||||
}
|
}
|
||||||
AST_RWLIST_UNLOCK(&channelvars);
|
AST_RWLIST_UNLOCK(channelvars);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ast_channel_set_manager_vars(size_t varc, char **vars)
|
||||||
|
{
|
||||||
|
channel_set_external_vars(&ami_vars, varc, vars);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ast_channel_set_ari_vars(size_t varc, char **vars)
|
||||||
|
{
|
||||||
|
channel_set_external_vars(&ari_vars, varc, vars);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -7839,14 +7863,15 @@ struct varshead *ast_channel_get_vars(struct ast_channel *chan)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct varshead *ast_channel_get_manager_vars(struct ast_channel *chan)
|
static struct varshead *channel_get_external_vars(struct external_vars *channelvars,
|
||||||
|
struct ast_channel *chan)
|
||||||
{
|
{
|
||||||
RAII_VAR(struct varshead *, ret, NULL, ao2_cleanup);
|
RAII_VAR(struct varshead *, ret, NULL, ao2_cleanup);
|
||||||
RAII_VAR(struct ast_str *, tmp, NULL, ast_free);
|
RAII_VAR(struct ast_str *, tmp, NULL, ast_free);
|
||||||
struct manager_channel_variable *mcv;
|
struct manager_channel_variable *mcv;
|
||||||
SCOPED_LOCK(lock, &channelvars, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
|
SCOPED_LOCK(lock, channelvars, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
|
||||||
|
|
||||||
if (AST_LIST_EMPTY(&channelvars)) {
|
if (AST_LIST_EMPTY(channelvars)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7857,7 +7882,7 @@ struct varshead *ast_channel_get_manager_vars(struct ast_channel *chan)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
AST_LIST_TRAVERSE(&channelvars, mcv, entry) {
|
AST_LIST_TRAVERSE(channelvars, mcv, entry) {
|
||||||
const char *val = NULL;
|
const char *val = NULL;
|
||||||
struct ast_var_t *var;
|
struct ast_var_t *var;
|
||||||
|
|
||||||
@@ -7882,11 +7907,23 @@ struct varshead *ast_channel_get_manager_vars(struct ast_channel *chan)
|
|||||||
|
|
||||||
ao2_ref(ret, +1);
|
ao2_ref(ret, +1);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct varshead *ast_channel_get_manager_vars(struct ast_channel *chan)
|
||||||
|
{
|
||||||
|
return channel_get_external_vars(&ami_vars, chan);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct varshead *ast_channel_get_ari_vars(struct ast_channel *chan)
|
||||||
|
{
|
||||||
|
return channel_get_external_vars(&ari_vars, chan);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void channels_shutdown(void)
|
static void channels_shutdown(void)
|
||||||
{
|
{
|
||||||
free_channelvars();
|
free_external_channelvars(&ami_vars);
|
||||||
|
free_external_channelvars(&ari_vars);
|
||||||
|
|
||||||
ast_data_unregister(NULL);
|
ast_data_unregister(NULL);
|
||||||
ast_cli_unregister_multiple(cli_channel, ARRAY_LEN(cli_channel));
|
ast_cli_unregister_multiple(cli_channel, ARRAY_LEN(cli_channel));
|
||||||
@@ -7919,6 +7956,9 @@ int ast_channels_init(void)
|
|||||||
|
|
||||||
ast_register_cleanup(channels_shutdown);
|
ast_register_cleanup(channels_shutdown);
|
||||||
|
|
||||||
|
AST_RWLIST_HEAD_INIT(&ami_vars);
|
||||||
|
AST_RWLIST_HEAD_INIT(&ari_vars);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
13
main/json.c
13
main/json.c
@@ -1048,3 +1048,16 @@ enum ast_json_to_ast_vars_code ast_json_to_ast_variables(struct ast_json *json_v
|
|||||||
|
|
||||||
return AST_JSON_TO_AST_VARS_CODE_SUCCESS;
|
return AST_JSON_TO_AST_VARS_CODE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ast_json *ast_json_channel_vars(struct varshead *channelvars)
|
||||||
|
{
|
||||||
|
struct ast_json *ret;
|
||||||
|
struct ast_var_t *var;
|
||||||
|
|
||||||
|
ret = ast_json_object_create();
|
||||||
|
AST_LIST_TRAVERSE(channelvars, var, entries) {
|
||||||
|
ast_json_object_set(ret, var->name, ast_json_string_create(var->value));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@@ -270,6 +270,7 @@ struct ast_channel_snapshot *ast_channel_snapshot_create(struct ast_channel *cha
|
|||||||
ast_set_flag(&snapshot->softhangup_flags, ast_channel_softhangup_internal_flag(chan));
|
ast_set_flag(&snapshot->softhangup_flags, ast_channel_softhangup_internal_flag(chan));
|
||||||
|
|
||||||
snapshot->manager_vars = ast_channel_get_manager_vars(chan);
|
snapshot->manager_vars = ast_channel_get_manager_vars(chan);
|
||||||
|
snapshot->ari_vars = ast_channel_get_ari_vars(chan);
|
||||||
snapshot->tech_properties = ast_channel_tech(chan)->properties;
|
snapshot->tech_properties = ast_channel_tech(chan)->properties;
|
||||||
|
|
||||||
return snapshot;
|
return snapshot;
|
||||||
@@ -918,6 +919,10 @@ struct ast_json *ast_channel_snapshot_to_json(
|
|||||||
"creationtime", ast_json_timeval(snapshot->creationtime, NULL),
|
"creationtime", ast_json_timeval(snapshot->creationtime, NULL),
|
||||||
"language", snapshot->language);
|
"language", snapshot->language);
|
||||||
|
|
||||||
|
if (snapshot->ari_vars && !AST_LIST_EMPTY(snapshot->ari_vars)) {
|
||||||
|
ast_json_object_set(json_chan, "channelvars", ast_json_channel_vars(snapshot->ari_vars));
|
||||||
|
}
|
||||||
|
|
||||||
return ast_json_ref(json_chan);
|
return ast_json_ref(json_chan);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1051,6 +1051,15 @@ int ast_ari_validate_channel(struct ast_json *json)
|
|||||||
res = 0;
|
res = 0;
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
|
if (strcmp("channelvars", ast_json_object_iter_key(iter)) == 0) {
|
||||||
|
int prop_is_valid;
|
||||||
|
prop_is_valid = ast_ari_validate_object(
|
||||||
|
ast_json_object_iter_value(iter));
|
||||||
|
if (!prop_is_valid) {
|
||||||
|
ast_log(LOG_ERROR, "ARI Channel field channelvars failed validation\n");
|
||||||
|
res = 0;
|
||||||
|
}
|
||||||
|
} else
|
||||||
if (strcmp("connected", ast_json_object_iter_key(iter)) == 0) {
|
if (strcmp("connected", ast_json_object_iter_key(iter)) == 0) {
|
||||||
int prop_is_valid;
|
int prop_is_valid;
|
||||||
has_connected = 1;
|
has_connected = 1;
|
||||||
|
@@ -1432,6 +1432,7 @@ ari_validator ast_ari_validate_application_fn(void);
|
|||||||
* Channel
|
* Channel
|
||||||
* - accountcode: string (required)
|
* - accountcode: string (required)
|
||||||
* - caller: CallerID (required)
|
* - caller: CallerID (required)
|
||||||
|
* - channelvars: object
|
||||||
* - connected: CallerID (required)
|
* - connected: CallerID (required)
|
||||||
* - creationtime: Date (required)
|
* - creationtime: Date (required)
|
||||||
* - dialplan: DialplanCEP (required)
|
* - dialplan: DialplanCEP (required)
|
||||||
|
@@ -26,6 +26,8 @@
|
|||||||
|
|
||||||
#include "asterisk/config_options.h"
|
#include "asterisk/config_options.h"
|
||||||
#include "asterisk/http_websocket.h"
|
#include "asterisk/http_websocket.h"
|
||||||
|
#include "asterisk/app.h"
|
||||||
|
#include "asterisk/channel.h"
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
/*! \brief Locking container for safe configuration access. */
|
/*! \brief Locking container for safe configuration access. */
|
||||||
@@ -316,6 +318,22 @@ static int process_config(int reload)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define MAX_VARS 128
|
||||||
|
|
||||||
|
static int channelvars_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
|
||||||
|
{
|
||||||
|
char *parse = NULL;
|
||||||
|
AST_DECLARE_APP_ARGS(args,
|
||||||
|
AST_APP_ARG(vars)[MAX_VARS];
|
||||||
|
);
|
||||||
|
|
||||||
|
parse = ast_strdupa(var->value);
|
||||||
|
AST_STANDARD_APP_ARGS(args, parse);
|
||||||
|
|
||||||
|
ast_channel_set_ari_vars(args.argc, args.vars);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int ast_ari_config_init(void)
|
int ast_ari_config_init(void)
|
||||||
{
|
{
|
||||||
if (aco_info_init(&cfg_info)) {
|
if (aco_info_init(&cfg_info)) {
|
||||||
@@ -339,6 +357,8 @@ int ast_ari_config_init(void)
|
|||||||
aco_option_register(&cfg_info, "websocket_write_timeout", ACO_EXACT, general_options,
|
aco_option_register(&cfg_info, "websocket_write_timeout", ACO_EXACT, general_options,
|
||||||
AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT_STR, OPT_INT_T, PARSE_IN_RANGE,
|
AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT_STR, OPT_INT_T, PARSE_IN_RANGE,
|
||||||
FLDSET(struct ast_ari_conf_general, write_timeout), 1, INT_MAX);
|
FLDSET(struct ast_ari_conf_general, write_timeout), 1, INT_MAX);
|
||||||
|
aco_option_register_custom(&cfg_info, "channelvars", ACO_EXACT, general_options,
|
||||||
|
"", channelvars_handler, 0);
|
||||||
|
|
||||||
/* ARI type=user category options */
|
/* ARI type=user category options */
|
||||||
aco_option_register(&cfg_info, "type", ACO_EXACT, user, NULL,
|
aco_option_register(&cfg_info, "type", ACO_EXACT, user, NULL,
|
||||||
|
@@ -112,6 +112,9 @@
|
|||||||
<configOption name="allowed_origins">
|
<configOption name="allowed_origins">
|
||||||
<synopsis>Comma separated list of allowed origins, for Cross-Origin Resource Sharing. May be set to * to allow all origins.</synopsis>
|
<synopsis>Comma separated list of allowed origins, for Cross-Origin Resource Sharing. May be set to * to allow all origins.</synopsis>
|
||||||
</configOption>
|
</configOption>
|
||||||
|
<configOption name="channelvars">
|
||||||
|
<synopsis>Comma separated list of channel variables to display in channel json.</synopsis>
|
||||||
|
</configOption>
|
||||||
</configObject>
|
</configObject>
|
||||||
|
|
||||||
<configObject name="user">
|
<configObject name="user">
|
||||||
|
@@ -1761,6 +1761,11 @@
|
|||||||
"required": true,
|
"required": true,
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The default spoken language"
|
"description": "The default spoken language"
|
||||||
|
},
|
||||||
|
"channelvars": {
|
||||||
|
"required": false,
|
||||||
|
"type": "object",
|
||||||
|
"description": "Channel variables"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user