[Asterisk-code-review] res ari: Add support for channel variables in ARI events. (asterisk[14])
Joshua Colp
asteriskteam at digium.com
Tue Nov 15 13:49:52 CST 2016
Joshua Colp has submitted this change and it was merged. ( https://gerrit.asterisk.org/4398 )
Change subject: res_ari: Add support for channel variables in ARI events.
......................................................................
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
---
M CHANGES
M configs/samples/ari.conf.sample
M include/asterisk/channel.h
M include/asterisk/json.h
M include/asterisk/stasis_channels.h
M main/channel.c
M main/json.c
M main/stasis_channels.c
M res/ari/ari_model_validators.c
M res/ari/ari_model_validators.h
M res/ari/config.c
M res/res_ari.c
M rest-api/api-docs/channels.json
13 files changed, 169 insertions(+), 19 deletions(-)
Approvals:
Anonymous Coward #1000019: Verified
Matt Jordan: Looks good to me, approved
Joshua Colp: Looks good to me, but someone else must approve
diff --git a/CHANGES b/CHANGES
index 91e8142..978a389 100644
--- a/CHANGES
+++ b/CHANGES
@@ -54,6 +54,12 @@
* A new dialplan variable, ABANDONED, is set when the call is not answered
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 ----------
------------------------------------------------------------------------------
diff --git a/configs/samples/ari.conf.sample b/configs/samples/ari.conf.sample
index 59f9a44..1294814 100644
--- a/configs/samples/ari.conf.sample
+++ b/configs/samples/ari.conf.sample
@@ -13,6 +13,11 @@
; receiving clients are slow to process the received information. Value is in
; milliseconds; default is 100 ms.
;websocket_write_timeout = 100
+;
+; Display certain channel variables every time a channel-oriented
+; event is emitted:
+;
+;channelvars = var1,var2,var3
;[username]
;type = user ; Specifies user configuration
diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index 78db878..c6371a0 100644
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -4330,6 +4330,36 @@
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
* \brief Gets the variables for a given channel, as set using pbx_builtin_setvar_helper().
*
diff --git a/include/asterisk/json.h b/include/asterisk/json.h
index cfd9a29..bd6ba86 100644
--- a/include/asterisk/json.h
+++ b/include/asterisk/json.h
@@ -1076,6 +1076,18 @@
*/
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 */
diff --git a/include/asterisk/stasis_channels.h b/include/asterisk/stasis_channels.h
index 6c6cd51..deb79b0 100644
--- a/include/asterisk/stasis_channels.h
+++ b/include/asterisk/stasis_channels.h
@@ -73,6 +73,7 @@
struct ast_flags softhangup_flags; /*!< softhangup channel flags */
struct varshead *manager_vars; /*!< Variables to be appended to manager events */
int tech_properties; /*!< Properties of the channel's technology */
+ struct varshead *ari_vars; /*!< Variables to be appended to ARI events */
};
/*!
diff --git a/main/channel.c b/main/channel.c
index 6e24ee6..8afeef0 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -7734,35 +7734,48 @@
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;
- AST_RWLIST_WRLOCK(&channelvars);
- while ((var = AST_RWLIST_REMOVE_HEAD(&channelvars, entry))) {
+ AST_RWLIST_WRLOCK(channelvars);
+ while ((var = AST_RWLIST_REMOVE_HEAD(channelvars, entry))) {
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;
- AST_RWLIST_RDLOCK(&channelvars);
- vars_present = !AST_LIST_EMPTY(&channelvars);
- AST_RWLIST_UNLOCK(&channelvars);
+ AST_RWLIST_RDLOCK(channelvars);
+ vars_present = !AST_LIST_EMPTY(channelvars);
+ AST_RWLIST_UNLOCK(channelvars);
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;
- free_channelvars();
- AST_RWLIST_WRLOCK(&channelvars);
+ free_external_channelvars(channelvars);
+ AST_RWLIST_WRLOCK(channelvars);
for (i = 0; i < varc; ++i) {
const char *var = vars[i];
struct manager_channel_variable *mcv;
@@ -7773,9 +7786,20 @@
if (strchr(var, '(')) {
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);
}
/*!
@@ -7817,14 +7841,15 @@
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 ast_str *, tmp, NULL, ast_free);
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;
}
@@ -7835,7 +7860,7 @@
return NULL;
}
- AST_LIST_TRAVERSE(&channelvars, mcv, entry) {
+ AST_LIST_TRAVERSE(channelvars, mcv, entry) {
const char *val = NULL;
struct ast_var_t *var;
@@ -7860,11 +7885,23 @@
ao2_ref(ret, +1);
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)
{
- free_channelvars();
+ free_external_channelvars(&ami_vars);
+ free_external_channelvars(&ari_vars);
ast_data_unregister(NULL);
ast_cli_unregister_multiple(cli_channel, ARRAY_LEN(cli_channel));
@@ -7897,6 +7934,9 @@
ast_register_cleanup(channels_shutdown);
+ AST_RWLIST_HEAD_INIT(&ami_vars);
+ AST_RWLIST_HEAD_INIT(&ari_vars);
+
return 0;
}
diff --git a/main/json.c b/main/json.c
index ca74f85..c03c4e5 100644
--- a/main/json.c
+++ b/main/json.c
@@ -1050,3 +1050,16 @@
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;
+}
diff --git a/main/stasis_channels.c b/main/stasis_channels.c
index e1c50c6..496def8 100644
--- a/main/stasis_channels.c
+++ b/main/stasis_channels.c
@@ -272,6 +272,7 @@
ast_set_flag(&snapshot->softhangup_flags, ast_channel_softhangup_internal_flag(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;
return snapshot;
@@ -920,6 +921,10 @@
"creationtime", ast_json_timeval(snapshot->creationtime, NULL),
"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);
}
diff --git a/res/ari/ari_model_validators.c b/res/ari/ari_model_validators.c
index 633a94c..20e2190 100644
--- a/res/ari/ari_model_validators.c
+++ b/res/ari/ari_model_validators.c
@@ -1053,6 +1053,15 @@
res = 0;
}
} 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) {
int prop_is_valid;
has_connected = 1;
diff --git a/res/ari/ari_model_validators.h b/res/ari/ari_model_validators.h
index 0b08ce8..fcd9fc1 100644
--- a/res/ari/ari_model_validators.h
+++ b/res/ari/ari_model_validators.h
@@ -1432,6 +1432,7 @@
* Channel
* - accountcode: string (required)
* - caller: CallerID (required)
+ * - channelvars: object
* - connected: CallerID (required)
* - creationtime: Date (required)
* - dialplan: DialplanCEP (required)
diff --git a/res/ari/config.c b/res/ari/config.c
index f8fdc27..5326a62 100644
--- a/res/ari/config.c
+++ b/res/ari/config.c
@@ -28,6 +28,8 @@
#include "asterisk/config_options.h"
#include "asterisk/http_websocket.h"
+#include "asterisk/app.h"
+#include "asterisk/channel.h"
#include "internal.h"
/*! \brief Locking container for safe configuration access. */
@@ -318,6 +320,22 @@
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)
{
if (aco_info_init(&cfg_info)) {
@@ -341,6 +359,8 @@
aco_option_register(&cfg_info, "websocket_write_timeout", ACO_EXACT, general_options,
AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT_STR, OPT_INT_T, PARSE_IN_RANGE,
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 */
aco_option_register(&cfg_info, "type", ACO_EXACT, user, NULL,
diff --git a/res/res_ari.c b/res/res_ari.c
index eb15a88..f976723 100644
--- a/res/res_ari.c
+++ b/res/res_ari.c
@@ -112,6 +112,9 @@
<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>
</configOption>
+ <configOption name="channelvars">
+ <synopsis>Comma separated list of channel variables to display in channel json.</synopsis>
+ </configOption>
</configObject>
<configObject name="user">
diff --git a/rest-api/api-docs/channels.json b/rest-api/api-docs/channels.json
index e707c06..bfa282e 100644
--- a/rest-api/api-docs/channels.json
+++ b/rest-api/api-docs/channels.json
@@ -1760,6 +1760,11 @@
"required": true,
"type": "string",
"description": "The default spoken language"
+ },
+ "channelvars": {
+ "required": false,
+ "type": "object",
+ "description": "Channel variables"
}
}
}
--
To view, visit https://gerrit.asterisk.org/4398
To unsubscribe, visit https://gerrit.asterisk.org/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I5609ba239259577c0948645df776d7f3bc864229
Gerrit-PatchSet: 2
Gerrit-Project: asterisk
Gerrit-Branch: 14
Gerrit-Owner: Sébastien Duthil <sduthil at proformatique.com>
Gerrit-Reviewer: Anonymous Coward #1000019
Gerrit-Reviewer: Joshua Colp <jcolp at digium.com>
Gerrit-Reviewer: Matt Jordan <mjordan at digium.com>
More information about the asterisk-code-review
mailing list