2013-04-15 16:43:47 +00:00
|
|
|
/*
|
|
|
|
* Asterisk -- An open source telephony toolkit.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2012 - 2013, Digium, Inc.
|
|
|
|
*
|
|
|
|
* David M. Lee, II <dlee@digium.com>
|
|
|
|
*
|
|
|
|
* See http://www.asterisk.org for more information about
|
|
|
|
* the Asterisk project. Please do not directly contact
|
|
|
|
* any of the maintainers of this project for assistance;
|
|
|
|
* the project provides a web site, mailing lists and IRC
|
|
|
|
* channels for your use.
|
|
|
|
*
|
|
|
|
* This program is free software, distributed under the terms of
|
|
|
|
* the GNU General Public License Version 2. See the LICENSE file
|
|
|
|
* at the top of the source tree.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*! \file
|
|
|
|
*
|
|
|
|
* \brief Stasis application support.
|
|
|
|
*
|
|
|
|
* \author David M. Lee, II <dlee@digium.com>
|
2013-05-14 21:45:08 +00:00
|
|
|
*
|
|
|
|
* <code>res_stasis.so</code> brings together the various components of the
|
|
|
|
* Stasis application infrastructure.
|
|
|
|
*
|
|
|
|
* First, there's the Stasis application handler, stasis_app_exec(). This is
|
|
|
|
* called by <code>app_stasis.so</code> to give control of a channel to the
|
|
|
|
* Stasis application code from the dialplan.
|
|
|
|
*
|
|
|
|
* While a channel is in stasis_app_exec(), it has a \ref stasis_app_control
|
|
|
|
* object, which may be used to control the channel.
|
|
|
|
*
|
|
|
|
* To control the channel, commands may be sent to channel using
|
|
|
|
* stasis_app_send_command() and stasis_app_send_async_command().
|
|
|
|
*
|
|
|
|
* Alongside this, applications may be registered/unregistered using
|
|
|
|
* stasis_app_register()/stasis_app_unregister(). While a channel is in Stasis,
|
|
|
|
* events received on the channel's topic are converted to JSON and forwarded to
|
|
|
|
* the \ref stasis_app_cb. The application may also subscribe to the channel to
|
|
|
|
* continue to receive messages even after the channel has left Stasis, but it
|
|
|
|
* will not be able to control it.
|
|
|
|
*
|
|
|
|
* Given all the stuff that comes together in this module, it's been broken up
|
|
|
|
* into several pieces that are in <code>res/stasis/</code> and compiled into
|
|
|
|
* <code>res_stasis.so</code>.
|
2013-04-15 16:43:47 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*** MODULEINFO
|
|
|
|
<support_level>core</support_level>
|
|
|
|
***/
|
|
|
|
|
|
|
|
#include "asterisk.h"
|
|
|
|
|
|
|
|
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
|
|
|
|
|
|
|
#include "asterisk/astobj2.h"
|
2013-05-14 21:45:08 +00:00
|
|
|
#include "asterisk/callerid.h"
|
2013-04-15 16:43:47 +00:00
|
|
|
#include "asterisk/module.h"
|
2013-05-14 21:45:08 +00:00
|
|
|
#include "asterisk/stasis_app_impl.h"
|
2013-04-15 16:43:47 +00:00
|
|
|
#include "asterisk/stasis_channels.h"
|
2013-07-25 04:18:05 +00:00
|
|
|
#include "asterisk/stasis_bridges.h"
|
2013-05-10 13:13:06 +00:00
|
|
|
#include "asterisk/stasis_message_router.h"
|
2013-05-14 21:45:08 +00:00
|
|
|
#include "asterisk/strings.h"
|
|
|
|
#include "stasis/app.h"
|
|
|
|
#include "stasis/control.h"
|
2013-08-23 00:26:19 +00:00
|
|
|
#include "asterisk/core_unreal.h"
|
|
|
|
#include "asterisk/musiconhold.h"
|
|
|
|
#include "asterisk/causes.h"
|
|
|
|
#include "asterisk/stringfields.h"
|
|
|
|
#include "asterisk/bridge_after.h"
|
2013-04-15 16:43:47 +00:00
|
|
|
|
2013-04-22 14:58:53 +00:00
|
|
|
/*! Time to wait for a frame in the application */
|
|
|
|
#define MAX_WAIT_MS 200
|
|
|
|
|
2013-04-15 16:43:47 +00:00
|
|
|
/*!
|
|
|
|
* \brief Number of buckets for the Stasis application hash table. Remember to
|
|
|
|
* keep it a prime number!
|
|
|
|
*/
|
|
|
|
#define APPS_NUM_BUCKETS 127
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Number of buckets for the Stasis application hash table. Remember to
|
|
|
|
* keep it a prime number!
|
|
|
|
*/
|
|
|
|
#define CONTROLS_NUM_BUCKETS 127
|
|
|
|
|
ARI: WebSocket event cleanup
Stasis events (which get distributed over the ARI WebSocket) are created
by subscribing to the channel_all_cached and bridge_all_cached topics,
filtering out events for channels/bridges currently subscribed to.
There are two issues with that. First was a race condition, where
messages in-flight to the master subscribe-to-all-things topic would get
sent out, even though the events happened before the channel was put
into Stasis. Secondly, as the number of channels and bridges grow in the
system, the work spent filtering messages becomes excessive.
Since r395954, individual channels and bridges have caching topics, and
can be subscribed to individually. This patch takes advantage, so that
channels and bridges are subscribed to on demand, instead of filtering
the global topics.
The one case where filtering is still required is handling BridgeMerge
messages, which are published directly to the bridge_all topic.
Other than the change to how subscriptions work, this patch mostly just
moves code around. Most of the work generating JSON objects from
messages was moved to .to_json handlers on the message types. The
callback functions handling app subscriptions were moved from res_stasis
(b/c they were global to the model) to stasis/app.c (b/c they are local
to the app now).
(closes issue ASTERISK-21969)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2754/
........
Merged revisions 397816 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397820 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-08-27 19:19:36 +00:00
|
|
|
/*!
|
|
|
|
* \brief Number of buckets for the Stasis bridges hash table. Remember to
|
|
|
|
* keep it a prime number!
|
|
|
|
*/
|
|
|
|
#define BRIDGES_NUM_BUCKETS 127
|
|
|
|
|
2013-04-15 16:43:47 +00:00
|
|
|
/*!
|
2013-05-14 21:45:08 +00:00
|
|
|
* \brief Stasis application container.
|
2013-04-15 16:43:47 +00:00
|
|
|
*/
|
2013-05-14 21:45:08 +00:00
|
|
|
struct ao2_container *apps_registry;
|
2013-04-15 16:43:47 +00:00
|
|
|
|
2013-05-14 21:45:08 +00:00
|
|
|
struct ao2_container *app_controls;
|
2013-04-15 16:43:47 +00:00
|
|
|
|
2013-06-10 13:07:11 +00:00
|
|
|
struct ao2_container *app_bridges;
|
|
|
|
|
2013-08-23 00:26:19 +00:00
|
|
|
struct ao2_container *app_bridges_moh;
|
|
|
|
|
2013-04-15 16:43:47 +00:00
|
|
|
/*! AO2 hash function for \ref app */
|
|
|
|
static int app_hash(const void *obj, const int flags)
|
|
|
|
{
|
|
|
|
const struct app *app = obj;
|
2013-05-14 21:45:08 +00:00
|
|
|
const char *name = flags & OBJ_KEY ? obj : app_name(app);
|
2013-04-15 16:43:47 +00:00
|
|
|
|
|
|
|
return ast_str_hash(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! AO2 comparison function for \ref app */
|
|
|
|
static int app_compare(void *lhs, void *rhs, int flags)
|
|
|
|
{
|
|
|
|
const struct app *lhs_app = lhs;
|
|
|
|
const struct app *rhs_app = rhs;
|
2013-05-14 21:45:08 +00:00
|
|
|
const char *lhs_name = app_name(lhs_app);
|
|
|
|
const char *rhs_name = flags & OBJ_KEY ? rhs : app_name(rhs_app);
|
2013-04-15 16:43:47 +00:00
|
|
|
|
2013-05-14 21:45:08 +00:00
|
|
|
if (strcmp(lhs_name, rhs_name) == 0) {
|
2013-04-15 16:43:47 +00:00
|
|
|
return CMP_MATCH | CMP_STOP;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! AO2 hash function for \ref stasis_app_control */
|
|
|
|
static int control_hash(const void *obj, const int flags)
|
|
|
|
{
|
|
|
|
const struct stasis_app_control *control = obj;
|
2013-05-14 21:45:08 +00:00
|
|
|
const char *id = flags & OBJ_KEY ?
|
|
|
|
obj : stasis_app_control_get_channel_id(control);
|
2013-04-15 16:43:47 +00:00
|
|
|
|
|
|
|
return ast_str_hash(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! AO2 comparison function for \ref stasis_app_control */
|
|
|
|
static int control_compare(void *lhs, void *rhs, int flags)
|
|
|
|
{
|
|
|
|
const struct stasis_app_control *lhs_control = lhs;
|
|
|
|
const struct stasis_app_control *rhs_control = rhs;
|
2013-05-14 21:45:08 +00:00
|
|
|
const char *lhs_id = stasis_app_control_get_channel_id(lhs_control);
|
|
|
|
const char *rhs_id = flags & OBJ_KEY ?
|
|
|
|
rhs : stasis_app_control_get_channel_id(rhs_control);
|
2013-04-15 16:43:47 +00:00
|
|
|
|
2013-05-14 21:45:08 +00:00
|
|
|
if (strcmp(lhs_id, rhs_id) == 0) {
|
2013-04-15 16:43:47 +00:00
|
|
|
return CMP_MATCH | CMP_STOP;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
ARI: WebSocket event cleanup
Stasis events (which get distributed over the ARI WebSocket) are created
by subscribing to the channel_all_cached and bridge_all_cached topics,
filtering out events for channels/bridges currently subscribed to.
There are two issues with that. First was a race condition, where
messages in-flight to the master subscribe-to-all-things topic would get
sent out, even though the events happened before the channel was put
into Stasis. Secondly, as the number of channels and bridges grow in the
system, the work spent filtering messages becomes excessive.
Since r395954, individual channels and bridges have caching topics, and
can be subscribed to individually. This patch takes advantage, so that
channels and bridges are subscribed to on demand, instead of filtering
the global topics.
The one case where filtering is still required is handling BridgeMerge
messages, which are published directly to the bridge_all topic.
Other than the change to how subscriptions work, this patch mostly just
moves code around. Most of the work generating JSON objects from
messages was moved to .to_json handlers on the message types. The
callback functions handling app subscriptions were moved from res_stasis
(b/c they were global to the model) to stasis/app.c (b/c they are local
to the app now).
(closes issue ASTERISK-21969)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2754/
........
Merged revisions 397816 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397820 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-08-27 19:19:36 +00:00
|
|
|
static int cleanup_cb(void *obj, void *arg, int flags)
|
|
|
|
{
|
|
|
|
struct app *app = obj;
|
|
|
|
|
|
|
|
if (!app_is_finished(app)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
ast_verb(1, "Shutting down application '%s'\n", app_name(app));
|
|
|
|
app_shutdown(app);
|
|
|
|
|
|
|
|
return CMP_MATCH;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Clean up any old apps that we don't need any more.
|
|
|
|
*/
|
|
|
|
static void cleanup(void)
|
|
|
|
{
|
|
|
|
ao2_callback(apps_registry, OBJ_MULTIPLE | OBJ_NODATA | OBJ_UNLINK,
|
|
|
|
cleanup_cb, NULL);
|
|
|
|
}
|
|
|
|
|
2013-07-19 19:35:21 +00:00
|
|
|
struct stasis_app_control *stasis_app_control_create(struct ast_channel *chan)
|
|
|
|
{
|
|
|
|
return control_create(chan);
|
|
|
|
}
|
|
|
|
|
2013-04-15 16:43:47 +00:00
|
|
|
struct stasis_app_control *stasis_app_control_find_by_channel(
|
|
|
|
const struct ast_channel *chan)
|
|
|
|
{
|
|
|
|
if (chan == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-04-22 14:58:53 +00:00
|
|
|
return stasis_app_control_find_by_channel_id(
|
|
|
|
ast_channel_uniqueid(chan));
|
|
|
|
}
|
|
|
|
|
|
|
|
struct stasis_app_control *stasis_app_control_find_by_channel_id(
|
|
|
|
const char *channel_id)
|
|
|
|
{
|
2013-05-14 21:45:08 +00:00
|
|
|
return ao2_find(app_controls, channel_id, OBJ_KEY);
|
2013-04-15 16:43:47 +00:00
|
|
|
}
|
|
|
|
|
2013-06-10 13:07:11 +00:00
|
|
|
/*! AO2 hash function for bridges container */
|
|
|
|
static int bridges_hash(const void *obj, const int flags)
|
|
|
|
{
|
|
|
|
const struct ast_bridge *bridge = obj;
|
|
|
|
const char *id = flags & OBJ_KEY ?
|
|
|
|
obj : bridge->uniqueid;
|
|
|
|
|
|
|
|
return ast_str_hash(id);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! AO2 comparison function for bridges container */
|
|
|
|
static int bridges_compare(void *lhs, void *rhs, int flags)
|
|
|
|
{
|
|
|
|
const struct ast_bridge *lhs_bridge = lhs;
|
|
|
|
const struct ast_bridge *rhs_bridge = rhs;
|
|
|
|
const char *lhs_id = lhs_bridge->uniqueid;
|
|
|
|
const char *rhs_id = flags & OBJ_KEY ?
|
|
|
|
rhs : rhs_bridge->uniqueid;
|
|
|
|
|
|
|
|
if (strcmp(lhs_id, rhs_id) == 0) {
|
|
|
|
return CMP_MATCH | CMP_STOP;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-23 00:26:19 +00:00
|
|
|
/*!
|
|
|
|
* Used with app_bridges_moh, provides links between bridges and existing music
|
|
|
|
* on hold channels that are being used with them.
|
|
|
|
*/
|
|
|
|
struct stasis_app_bridge_moh_wrapper {
|
|
|
|
AST_DECLARE_STRING_FIELDS(
|
|
|
|
AST_STRING_FIELD(channel_id);
|
|
|
|
AST_STRING_FIELD(bridge_id);
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
static void stasis_app_bridge_moh_wrapper_destructor(void *obj)
|
|
|
|
{
|
|
|
|
struct stasis_app_bridge_moh_wrapper *wrapper = obj;
|
|
|
|
ast_string_field_free_memory(wrapper);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! AO2 hash function for the bridges moh container */
|
|
|
|
static int bridges_moh_hash_fn(const void *obj, const int flags)
|
|
|
|
{
|
|
|
|
const struct stasis_app_bridge_moh_wrapper *wrapper;
|
|
|
|
const char *key;
|
|
|
|
|
|
|
|
switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
|
|
|
|
case OBJ_KEY:
|
|
|
|
key = obj;
|
|
|
|
return ast_str_hash(key);
|
|
|
|
case OBJ_POINTER:
|
|
|
|
wrapper = obj;
|
|
|
|
return ast_str_hash(wrapper->bridge_id);
|
|
|
|
default:
|
|
|
|
/* Hash can only work on something with a full key. */
|
|
|
|
ast_assert(0);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int bridges_moh_sort_fn(const void *obj_left, const void *obj_right, const int flags)
|
|
|
|
{
|
|
|
|
const struct stasis_app_bridge_moh_wrapper *left = obj_left;
|
|
|
|
const struct stasis_app_bridge_moh_wrapper *right = obj_right;
|
|
|
|
const char *right_key = obj_right;
|
|
|
|
int cmp;
|
|
|
|
|
|
|
|
switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
|
|
|
|
case OBJ_POINTER:
|
|
|
|
right_key = right->bridge_id;
|
|
|
|
/* Fall through */
|
|
|
|
case OBJ_KEY:
|
|
|
|
cmp = strcmp(left->bridge_id, right_key);
|
|
|
|
break;
|
|
|
|
case OBJ_PARTIAL_KEY:
|
|
|
|
cmp = strncmp(left->bridge_id, right_key, strlen(right_key));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* Sort can only work on something with a full or partial key. */
|
|
|
|
ast_assert(0);
|
|
|
|
cmp = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return cmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! Removes the bridge to music on hold channel link */
|
|
|
|
static void remove_bridge_moh(char *bridge_id)
|
|
|
|
{
|
|
|
|
RAII_VAR(struct stasis_app_bridge_moh_wrapper *, moh_wrapper, ao2_find(app_bridges_moh, bridge_id, OBJ_KEY), ao2_cleanup);
|
|
|
|
|
|
|
|
if (moh_wrapper) {
|
|
|
|
ao2_unlink_flags(app_bridges_moh, moh_wrapper, OBJ_NOLOCK);
|
|
|
|
}
|
|
|
|
ast_free(bridge_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! After bridge failure callback for moh channels */
|
|
|
|
static void moh_after_bridge_cb_failed(enum ast_bridge_after_cb_reason reason, void *data)
|
|
|
|
{
|
|
|
|
char *bridge_id = data;
|
|
|
|
|
|
|
|
remove_bridge_moh(bridge_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! After bridge callback for moh channels */
|
|
|
|
static void moh_after_bridge_cb(struct ast_channel *chan, void *data)
|
|
|
|
{
|
|
|
|
char *bridge_id = data;
|
|
|
|
|
|
|
|
remove_bridge_moh(bridge_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! Request a bridge MOH channel */
|
|
|
|
static struct ast_channel *prepare_bridge_moh_channel(void)
|
|
|
|
{
|
|
|
|
RAII_VAR(struct ast_format_cap *, cap, NULL, ast_format_cap_destroy);
|
|
|
|
struct ast_format format;
|
|
|
|
|
|
|
|
cap = ast_format_cap_alloc_nolock();
|
|
|
|
if (!cap) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ast_format_cap_add(cap, ast_format_set(&format, AST_FORMAT_SLINEAR, 0));
|
|
|
|
|
|
|
|
return ast_request("Announcer", cap, NULL, "ARI_MOH", NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*! Provides the moh channel with a thread so it can actually play its music */
|
|
|
|
static void *moh_channel_thread(void *data)
|
|
|
|
{
|
|
|
|
struct ast_channel *moh_channel = data;
|
|
|
|
|
|
|
|
while (!ast_safe_sleep(moh_channel, 1000));
|
|
|
|
|
|
|
|
ast_moh_stop(moh_channel);
|
|
|
|
ast_hangup(moh_channel);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* \internal
|
|
|
|
* \brief Creates, pushes, and links a channel for playing music on hold to bridge
|
|
|
|
*
|
|
|
|
* \param bridge Which bridge this moh channel exists for
|
|
|
|
*
|
|
|
|
* \retval NULL if the channel could not be created, pushed, or linked
|
|
|
|
* \retval Reference to the channel on success
|
|
|
|
*/
|
|
|
|
static struct ast_channel *bridge_moh_create(struct ast_bridge *bridge)
|
|
|
|
{
|
|
|
|
RAII_VAR(struct stasis_app_bridge_moh_wrapper *, new_wrapper, NULL, ao2_cleanup);
|
|
|
|
RAII_VAR(char *, bridge_id, ast_strdup(bridge->uniqueid), ast_free);
|
|
|
|
struct ast_channel *chan;
|
|
|
|
pthread_t threadid;
|
|
|
|
|
|
|
|
if (!bridge_id) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
chan = prepare_bridge_moh_channel();
|
|
|
|
|
|
|
|
if (!chan) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The after bridge callback assumes responsibility of the bridge_id. */
|
|
|
|
ast_bridge_set_after_callback(chan, moh_after_bridge_cb, moh_after_bridge_cb_failed, bridge_id);
|
|
|
|
|
|
|
|
bridge_id = NULL;
|
|
|
|
|
|
|
|
if (ast_unreal_channel_push_to_bridge(chan, bridge,
|
|
|
|
AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE | AST_BRIDGE_CHANNEL_FLAG_LONELY)) {
|
|
|
|
ast_hangup(chan);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
new_wrapper = ao2_alloc_options(sizeof(*new_wrapper), stasis_app_bridge_moh_wrapper_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK);
|
|
|
|
if (!new_wrapper) {
|
|
|
|
ast_hangup(chan);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ast_string_field_init(new_wrapper, 32)) {
|
|
|
|
ast_hangup(chan);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ast_string_field_set(new_wrapper, bridge_id, bridge->uniqueid);
|
|
|
|
ast_string_field_set(new_wrapper, channel_id, ast_channel_uniqueid(chan));
|
|
|
|
|
|
|
|
if (!ao2_link(app_bridges_moh, new_wrapper)) {
|
|
|
|
ast_hangup(chan);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ast_pthread_create_detached(&threadid, NULL, moh_channel_thread, chan)) {
|
|
|
|
ast_log(LOG_ERROR, "Failed to create channel thread. Abandoning MOH channel creation.\n");
|
|
|
|
ao2_unlink_flags(app_bridges_moh, new_wrapper, OBJ_NOLOCK);
|
|
|
|
ast_hangup(chan);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return chan;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ast_channel *stasis_app_bridge_moh_channel(struct ast_bridge *bridge)
|
|
|
|
{
|
|
|
|
RAII_VAR(struct stasis_app_bridge_moh_wrapper *, moh_wrapper, NULL, ao2_cleanup);
|
|
|
|
|
|
|
|
SCOPED_AO2LOCK(lock, app_bridges_moh);
|
|
|
|
|
|
|
|
moh_wrapper = ao2_find(app_bridges_moh, bridge->uniqueid, OBJ_KEY | OBJ_NOLOCK);
|
|
|
|
|
|
|
|
if (!moh_wrapper) {
|
|
|
|
struct ast_channel *bridge_moh_channel = bridge_moh_create(bridge);
|
|
|
|
return bridge_moh_channel;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ast_channel_get_by_name(moh_wrapper->channel_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
int stasis_app_bridge_moh_stop(struct ast_bridge *bridge)
|
|
|
|
{
|
|
|
|
RAII_VAR(struct stasis_app_bridge_moh_wrapper *, moh_wrapper, NULL, ao2_cleanup);
|
|
|
|
struct ast_channel *chan;
|
|
|
|
|
|
|
|
SCOPED_AO2LOCK(lock, app_bridges_moh);
|
|
|
|
|
|
|
|
moh_wrapper = ao2_find(app_bridges_moh, bridge->uniqueid, OBJ_KEY | OBJ_NOLOCK);
|
|
|
|
|
|
|
|
if (!moh_wrapper) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
chan = ast_channel_get_by_name(moh_wrapper->channel_id);
|
|
|
|
if (!chan) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ast_moh_stop(chan);
|
|
|
|
ast_softhangup(chan, AST_CAUSE_NORMAL_CLEARING);
|
|
|
|
ao2_cleanup(chan);
|
|
|
|
|
|
|
|
ao2_unlink_flags(app_bridges_moh, moh_wrapper, OBJ_NOLOCK);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-06-10 13:07:11 +00:00
|
|
|
struct ast_bridge *stasis_app_bridge_find_by_id(
|
|
|
|
const char *bridge_id)
|
|
|
|
{
|
|
|
|
return ao2_find(app_bridges, bridge_id, OBJ_KEY);
|
|
|
|
}
|
|
|
|
|
2013-04-15 16:43:47 +00:00
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief In addition to running ao2_cleanup(), this function also removes the
|
2013-06-10 13:07:11 +00:00
|
|
|
* object from the app_controls container.
|
2013-04-15 16:43:47 +00:00
|
|
|
*/
|
|
|
|
static void control_unlink(struct stasis_app_control *control)
|
|
|
|
{
|
|
|
|
if (!control) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-05-14 21:45:08 +00:00
|
|
|
ao2_unlink_flags(app_controls, control,
|
|
|
|
OBJ_POINTER | OBJ_UNLINK | OBJ_NODATA);
|
2013-04-15 16:43:47 +00:00
|
|
|
ao2_cleanup(control);
|
|
|
|
}
|
|
|
|
|
2013-06-10 13:07:11 +00:00
|
|
|
struct ast_bridge *stasis_app_bridge_create(const char *type)
|
|
|
|
{
|
|
|
|
struct ast_bridge *bridge;
|
2013-08-15 12:05:41 +00:00
|
|
|
int capabilities, flags = AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM | AST_BRIDGE_FLAG_MERGE_INHIBIT_TO
|
|
|
|
| AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM | AST_BRIDGE_FLAG_SWAP_INHIBIT_TO
|
|
|
|
| AST_BRIDGE_FLAG_TRANSFER_PROHIBITED;
|
|
|
|
|
2013-06-10 13:07:11 +00:00
|
|
|
if (ast_strlen_zero(type) || !strcmp(type, "mixing")) {
|
|
|
|
capabilities = AST_BRIDGE_CAPABILITY_1TO1MIX |
|
|
|
|
AST_BRIDGE_CAPABILITY_MULTIMIX |
|
|
|
|
AST_BRIDGE_CAPABILITY_NATIVE;
|
2013-08-15 12:05:41 +00:00
|
|
|
flags |= AST_BRIDGE_FLAG_SMART;
|
2013-06-10 13:07:11 +00:00
|
|
|
} else if (!strcmp(type, "holding")) {
|
|
|
|
capabilities = AST_BRIDGE_CAPABILITY_HOLDING;
|
|
|
|
} else {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bridge = ast_bridge_base_new(capabilities, flags);
|
|
|
|
if (bridge) {
|
|
|
|
ao2_link(app_bridges, bridge);
|
|
|
|
}
|
|
|
|
return bridge;
|
|
|
|
}
|
|
|
|
|
|
|
|
void stasis_app_bridge_destroy(const char *bridge_id)
|
|
|
|
{
|
|
|
|
struct ast_bridge *bridge = stasis_app_bridge_find_by_id(bridge_id);
|
|
|
|
if (!bridge) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ao2_unlink(app_bridges, bridge);
|
2013-08-22 21:09:52 +00:00
|
|
|
ast_bridge_destroy(bridge, 0);
|
2013-06-10 13:07:11 +00:00
|
|
|
}
|
|
|
|
|
ARI: WebSocket event cleanup
Stasis events (which get distributed over the ARI WebSocket) are created
by subscribing to the channel_all_cached and bridge_all_cached topics,
filtering out events for channels/bridges currently subscribed to.
There are two issues with that. First was a race condition, where
messages in-flight to the master subscribe-to-all-things topic would get
sent out, even though the events happened before the channel was put
into Stasis. Secondly, as the number of channels and bridges grow in the
system, the work spent filtering messages becomes excessive.
Since r395954, individual channels and bridges have caching topics, and
can be subscribed to individually. This patch takes advantage, so that
channels and bridges are subscribed to on demand, instead of filtering
the global topics.
The one case where filtering is still required is handling BridgeMerge
messages, which are published directly to the bridge_all topic.
Other than the change to how subscriptions work, this patch mostly just
moves code around. Most of the work generating JSON objects from
messages was moved to .to_json handlers on the message types. The
callback functions handling app subscriptions were moved from res_stasis
(b/c they were global to the model) to stasis/app.c (b/c they are local
to the app now).
(closes issue ASTERISK-21969)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2754/
........
Merged revisions 397816 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397820 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-08-27 19:19:36 +00:00
|
|
|
static int send_start_msg(struct app *app, struct ast_channel *chan,
|
2013-05-14 21:45:08 +00:00
|
|
|
int argc, char *argv[])
|
2013-04-22 14:58:53 +00:00
|
|
|
{
|
2013-05-14 21:45:08 +00:00
|
|
|
RAII_VAR(struct ast_json *, msg, NULL, ast_json_unref);
|
|
|
|
RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
|
|
|
|
|
|
|
|
struct ast_json *json_args;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
ast_assert(chan != NULL);
|
|
|
|
|
|
|
|
/* Set channel info */
|
|
|
|
snapshot = ast_channel_snapshot_create(chan);
|
|
|
|
if (!snapshot) {
|
|
|
|
return -1;
|
|
|
|
}
|
2013-04-22 14:58:53 +00:00
|
|
|
|
ARI: WebSocket event cleanup
Stasis events (which get distributed over the ARI WebSocket) are created
by subscribing to the channel_all_cached and bridge_all_cached topics,
filtering out events for channels/bridges currently subscribed to.
There are two issues with that. First was a race condition, where
messages in-flight to the master subscribe-to-all-things topic would get
sent out, even though the events happened before the channel was put
into Stasis. Secondly, as the number of channels and bridges grow in the
system, the work spent filtering messages becomes excessive.
Since r395954, individual channels and bridges have caching topics, and
can be subscribed to individually. This patch takes advantage, so that
channels and bridges are subscribed to on demand, instead of filtering
the global topics.
The one case where filtering is still required is handling BridgeMerge
messages, which are published directly to the bridge_all topic.
Other than the change to how subscriptions work, this patch mostly just
moves code around. Most of the work generating JSON objects from
messages was moved to .to_json handlers on the message types. The
callback functions handling app subscriptions were moved from res_stasis
(b/c they were global to the model) to stasis/app.c (b/c they are local
to the app now).
(closes issue ASTERISK-21969)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2754/
........
Merged revisions 397816 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397820 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-08-27 19:19:36 +00:00
|
|
|
msg = ast_json_pack("{s: s, s: o, s: [], s: o}",
|
Update events to use Swagger 1.3 subtyping, and related aftermath
This patch started with the simple idea of changing the /events data
model to be more sane. The original model would send out events like:
{ "stasis_start": { "args": [], "channel": { ... } } }
The event discriminator was the field name instead of being a value in
the object, due to limitations in how Swagger 1.1 could model objects.
While technically sufficient in communicating event information, it was
really difficult to deal with in terms of client side JSON handling.
This patch takes advantage of a proposed extension[1] to Swagger which
allows type variance through the use of a discriminator field. This had
a domino effect that made this a surprisingly large patch.
[1]: https://groups.google.com/d/msg/wordnik-api/EC3rGajE0os/ey_5dBI_jWcJ
In changing the models, I also had to change the swagger_model.py
processor so it can handle the type discriminator and subtyping. I took
that a big step forward, and using that information to generate an
ari_model module, which can validate a JSON object against the Swagger
model.
The REST and WebSocket generators were changed to take advantage of the
validators. If compiled with AST_DEVMODE enabled, JSON objects that
don't match their corresponding models will not be sent out. For REST
API calls, a 500 Internal Server response is sent. For WebSockets, the
invalid JSON message is replaced with an error message.
Since this took over about half of the job of the existing JSON
generators, and the .to_json virtual function on messages took over the
other half, I reluctantly removed the generators.
The validators turned up all sorts of errors and inconsistencies in our
data models, and the code. These were cleaned up, with checks in the
code generator avoid some of the consistency problems in the future.
* The model for a channel snapshot was trimmed down to match the
information sent via AMI. Many of the field being sent were not
useful in the general case.
* The model for a bridge snapshot was updated to be more consistent
with the other ARI models.
Another impact of introducing subtyping was that the swagger-codegen
documentation generator was insufficient (at least until it catches up
with Swagger 1.2). I wanted it to be easier to generate docs for the API
anyways, so I ported the wiki pages to use the Asterisk Swagger
generator. In the process, I was able to clean up many of the model
links, which would occasionally give inconsistent results on the wiki. I
also added error responses to the wiki docs, making the wiki
documentation more complete.
Finally, since Stasis-HTTP will now be named Asterisk REST Interface
(ARI), any new functions and files I created carry the ari_ prefix. I
changed a few stasis_http references to ari where it was non-intrusive
and made sense.
(closes issue ASTERISK-21885)
Review: https://reviewboard.asterisk.org/r/2639/
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@393529 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-07-03 16:32:41 +00:00
|
|
|
"type", "StasisStart",
|
ARI: WebSocket event cleanup
Stasis events (which get distributed over the ARI WebSocket) are created
by subscribing to the channel_all_cached and bridge_all_cached topics,
filtering out events for channels/bridges currently subscribed to.
There are two issues with that. First was a race condition, where
messages in-flight to the master subscribe-to-all-things topic would get
sent out, even though the events happened before the channel was put
into Stasis. Secondly, as the number of channels and bridges grow in the
system, the work spent filtering messages becomes excessive.
Since r395954, individual channels and bridges have caching topics, and
can be subscribed to individually. This patch takes advantage, so that
channels and bridges are subscribed to on demand, instead of filtering
the global topics.
The one case where filtering is still required is handling BridgeMerge
messages, which are published directly to the bridge_all topic.
Other than the change to how subscriptions work, this patch mostly just
moves code around. Most of the work generating JSON objects from
messages was moved to .to_json handlers on the message types. The
callback functions handling app subscriptions were moved from res_stasis
(b/c they were global to the model) to stasis/app.c (b/c they are local
to the app now).
(closes issue ASTERISK-21969)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2754/
........
Merged revisions 397816 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397820 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-08-27 19:19:36 +00:00
|
|
|
"timestamp", ast_json_timeval(ast_tvnow(), NULL),
|
Update events to use Swagger 1.3 subtyping, and related aftermath
This patch started with the simple idea of changing the /events data
model to be more sane. The original model would send out events like:
{ "stasis_start": { "args": [], "channel": { ... } } }
The event discriminator was the field name instead of being a value in
the object, due to limitations in how Swagger 1.1 could model objects.
While technically sufficient in communicating event information, it was
really difficult to deal with in terms of client side JSON handling.
This patch takes advantage of a proposed extension[1] to Swagger which
allows type variance through the use of a discriminator field. This had
a domino effect that made this a surprisingly large patch.
[1]: https://groups.google.com/d/msg/wordnik-api/EC3rGajE0os/ey_5dBI_jWcJ
In changing the models, I also had to change the swagger_model.py
processor so it can handle the type discriminator and subtyping. I took
that a big step forward, and using that information to generate an
ari_model module, which can validate a JSON object against the Swagger
model.
The REST and WebSocket generators were changed to take advantage of the
validators. If compiled with AST_DEVMODE enabled, JSON objects that
don't match their corresponding models will not be sent out. For REST
API calls, a 500 Internal Server response is sent. For WebSockets, the
invalid JSON message is replaced with an error message.
Since this took over about half of the job of the existing JSON
generators, and the .to_json virtual function on messages took over the
other half, I reluctantly removed the generators.
The validators turned up all sorts of errors and inconsistencies in our
data models, and the code. These were cleaned up, with checks in the
code generator avoid some of the consistency problems in the future.
* The model for a channel snapshot was trimmed down to match the
information sent via AMI. Many of the field being sent were not
useful in the general case.
* The model for a bridge snapshot was updated to be more consistent
with the other ARI models.
Another impact of introducing subtyping was that the swagger-codegen
documentation generator was insufficient (at least until it catches up
with Swagger 1.2). I wanted it to be easier to generate docs for the API
anyways, so I ported the wiki pages to use the Asterisk Swagger
generator. In the process, I was able to clean up many of the model
links, which would occasionally give inconsistent results on the wiki. I
also added error responses to the wiki docs, making the wiki
documentation more complete.
Finally, since Stasis-HTTP will now be named Asterisk REST Interface
(ARI), any new functions and files I created carry the ari_ prefix. I
changed a few stasis_http references to ari where it was non-intrusive
and made sense.
(closes issue ASTERISK-21885)
Review: https://reviewboard.asterisk.org/r/2639/
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@393529 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-07-03 16:32:41 +00:00
|
|
|
"args",
|
|
|
|
"channel", ast_channel_snapshot_to_json(snapshot));
|
|
|
|
if (!msg) {
|
2013-05-14 21:45:08 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2013-04-22 14:58:53 +00:00
|
|
|
|
2013-05-14 21:45:08 +00:00
|
|
|
/* Append arguments to args array */
|
Update events to use Swagger 1.3 subtyping, and related aftermath
This patch started with the simple idea of changing the /events data
model to be more sane. The original model would send out events like:
{ "stasis_start": { "args": [], "channel": { ... } } }
The event discriminator was the field name instead of being a value in
the object, due to limitations in how Swagger 1.1 could model objects.
While technically sufficient in communicating event information, it was
really difficult to deal with in terms of client side JSON handling.
This patch takes advantage of a proposed extension[1] to Swagger which
allows type variance through the use of a discriminator field. This had
a domino effect that made this a surprisingly large patch.
[1]: https://groups.google.com/d/msg/wordnik-api/EC3rGajE0os/ey_5dBI_jWcJ
In changing the models, I also had to change the swagger_model.py
processor so it can handle the type discriminator and subtyping. I took
that a big step forward, and using that information to generate an
ari_model module, which can validate a JSON object against the Swagger
model.
The REST and WebSocket generators were changed to take advantage of the
validators. If compiled with AST_DEVMODE enabled, JSON objects that
don't match their corresponding models will not be sent out. For REST
API calls, a 500 Internal Server response is sent. For WebSockets, the
invalid JSON message is replaced with an error message.
Since this took over about half of the job of the existing JSON
generators, and the .to_json virtual function on messages took over the
other half, I reluctantly removed the generators.
The validators turned up all sorts of errors and inconsistencies in our
data models, and the code. These were cleaned up, with checks in the
code generator avoid some of the consistency problems in the future.
* The model for a channel snapshot was trimmed down to match the
information sent via AMI. Many of the field being sent were not
useful in the general case.
* The model for a bridge snapshot was updated to be more consistent
with the other ARI models.
Another impact of introducing subtyping was that the swagger-codegen
documentation generator was insufficient (at least until it catches up
with Swagger 1.2). I wanted it to be easier to generate docs for the API
anyways, so I ported the wiki pages to use the Asterisk Swagger
generator. In the process, I was able to clean up many of the model
links, which would occasionally give inconsistent results on the wiki. I
also added error responses to the wiki docs, making the wiki
documentation more complete.
Finally, since Stasis-HTTP will now be named Asterisk REST Interface
(ARI), any new functions and files I created carry the ari_ prefix. I
changed a few stasis_http references to ari where it was non-intrusive
and made sense.
(closes issue ASTERISK-21885)
Review: https://reviewboard.asterisk.org/r/2639/
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@393529 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-07-03 16:32:41 +00:00
|
|
|
json_args = ast_json_object_get(msg, "args");
|
2013-05-14 21:45:08 +00:00
|
|
|
ast_assert(json_args != NULL);
|
|
|
|
for (i = 0; i < argc; ++i) {
|
|
|
|
int r = ast_json_array_append(json_args,
|
|
|
|
ast_json_string_create(argv[i]));
|
|
|
|
if (r != 0) {
|
|
|
|
ast_log(LOG_ERROR, "Error appending start message\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
2013-04-22 14:58:53 +00:00
|
|
|
|
2013-05-14 21:45:08 +00:00
|
|
|
app_send(app, msg);
|
|
|
|
return 0;
|
2013-04-22 14:58:53 +00:00
|
|
|
}
|
|
|
|
|
ARI: WebSocket event cleanup
Stasis events (which get distributed over the ARI WebSocket) are created
by subscribing to the channel_all_cached and bridge_all_cached topics,
filtering out events for channels/bridges currently subscribed to.
There are two issues with that. First was a race condition, where
messages in-flight to the master subscribe-to-all-things topic would get
sent out, even though the events happened before the channel was put
into Stasis. Secondly, as the number of channels and bridges grow in the
system, the work spent filtering messages becomes excessive.
Since r395954, individual channels and bridges have caching topics, and
can be subscribed to individually. This patch takes advantage, so that
channels and bridges are subscribed to on demand, instead of filtering
the global topics.
The one case where filtering is still required is handling BridgeMerge
messages, which are published directly to the bridge_all topic.
Other than the change to how subscriptions work, this patch mostly just
moves code around. Most of the work generating JSON objects from
messages was moved to .to_json handlers on the message types. The
callback functions handling app subscriptions were moved from res_stasis
(b/c they were global to the model) to stasis/app.c (b/c they are local
to the app now).
(closes issue ASTERISK-21969)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2754/
........
Merged revisions 397816 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397820 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-08-27 19:19:36 +00:00
|
|
|
static int send_end_msg(struct app *app, struct ast_channel *chan)
|
2013-05-14 21:45:08 +00:00
|
|
|
{
|
|
|
|
RAII_VAR(struct ast_json *, msg, NULL, ast_json_unref);
|
|
|
|
RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
|
|
|
|
|
|
|
|
ast_assert(chan != NULL);
|
|
|
|
|
|
|
|
/* Set channel info */
|
|
|
|
snapshot = ast_channel_snapshot_create(chan);
|
|
|
|
if (snapshot == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
ARI: WebSocket event cleanup
Stasis events (which get distributed over the ARI WebSocket) are created
by subscribing to the channel_all_cached and bridge_all_cached topics,
filtering out events for channels/bridges currently subscribed to.
There are two issues with that. First was a race condition, where
messages in-flight to the master subscribe-to-all-things topic would get
sent out, even though the events happened before the channel was put
into Stasis. Secondly, as the number of channels and bridges grow in the
system, the work spent filtering messages becomes excessive.
Since r395954, individual channels and bridges have caching topics, and
can be subscribed to individually. This patch takes advantage, so that
channels and bridges are subscribed to on demand, instead of filtering
the global topics.
The one case where filtering is still required is handling BridgeMerge
messages, which are published directly to the bridge_all topic.
Other than the change to how subscriptions work, this patch mostly just
moves code around. Most of the work generating JSON objects from
messages was moved to .to_json handlers on the message types. The
callback functions handling app subscriptions were moved from res_stasis
(b/c they were global to the model) to stasis/app.c (b/c they are local
to the app now).
(closes issue ASTERISK-21969)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2754/
........
Merged revisions 397816 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397820 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-08-27 19:19:36 +00:00
|
|
|
msg = ast_json_pack("{s: s, s: o, s: o}",
|
Update events to use Swagger 1.3 subtyping, and related aftermath
This patch started with the simple idea of changing the /events data
model to be more sane. The original model would send out events like:
{ "stasis_start": { "args": [], "channel": { ... } } }
The event discriminator was the field name instead of being a value in
the object, due to limitations in how Swagger 1.1 could model objects.
While technically sufficient in communicating event information, it was
really difficult to deal with in terms of client side JSON handling.
This patch takes advantage of a proposed extension[1] to Swagger which
allows type variance through the use of a discriminator field. This had
a domino effect that made this a surprisingly large patch.
[1]: https://groups.google.com/d/msg/wordnik-api/EC3rGajE0os/ey_5dBI_jWcJ
In changing the models, I also had to change the swagger_model.py
processor so it can handle the type discriminator and subtyping. I took
that a big step forward, and using that information to generate an
ari_model module, which can validate a JSON object against the Swagger
model.
The REST and WebSocket generators were changed to take advantage of the
validators. If compiled with AST_DEVMODE enabled, JSON objects that
don't match their corresponding models will not be sent out. For REST
API calls, a 500 Internal Server response is sent. For WebSockets, the
invalid JSON message is replaced with an error message.
Since this took over about half of the job of the existing JSON
generators, and the .to_json virtual function on messages took over the
other half, I reluctantly removed the generators.
The validators turned up all sorts of errors and inconsistencies in our
data models, and the code. These were cleaned up, with checks in the
code generator avoid some of the consistency problems in the future.
* The model for a channel snapshot was trimmed down to match the
information sent via AMI. Many of the field being sent were not
useful in the general case.
* The model for a bridge snapshot was updated to be more consistent
with the other ARI models.
Another impact of introducing subtyping was that the swagger-codegen
documentation generator was insufficient (at least until it catches up
with Swagger 1.2). I wanted it to be easier to generate docs for the API
anyways, so I ported the wiki pages to use the Asterisk Swagger
generator. In the process, I was able to clean up many of the model
links, which would occasionally give inconsistent results on the wiki. I
also added error responses to the wiki docs, making the wiki
documentation more complete.
Finally, since Stasis-HTTP will now be named Asterisk REST Interface
(ARI), any new functions and files I created carry the ari_ prefix. I
changed a few stasis_http references to ari where it was non-intrusive
and made sense.
(closes issue ASTERISK-21885)
Review: https://reviewboard.asterisk.org/r/2639/
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@393529 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-07-03 16:32:41 +00:00
|
|
|
"type", "StasisEnd",
|
ARI: WebSocket event cleanup
Stasis events (which get distributed over the ARI WebSocket) are created
by subscribing to the channel_all_cached and bridge_all_cached topics,
filtering out events for channels/bridges currently subscribed to.
There are two issues with that. First was a race condition, where
messages in-flight to the master subscribe-to-all-things topic would get
sent out, even though the events happened before the channel was put
into Stasis. Secondly, as the number of channels and bridges grow in the
system, the work spent filtering messages becomes excessive.
Since r395954, individual channels and bridges have caching topics, and
can be subscribed to individually. This patch takes advantage, so that
channels and bridges are subscribed to on demand, instead of filtering
the global topics.
The one case where filtering is still required is handling BridgeMerge
messages, which are published directly to the bridge_all topic.
Other than the change to how subscriptions work, this patch mostly just
moves code around. Most of the work generating JSON objects from
messages was moved to .to_json handlers on the message types. The
callback functions handling app subscriptions were moved from res_stasis
(b/c they were global to the model) to stasis/app.c (b/c they are local
to the app now).
(closes issue ASTERISK-21969)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2754/
........
Merged revisions 397816 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397820 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-08-27 19:19:36 +00:00
|
|
|
"timestamp", ast_json_timeval(ast_tvnow(), NULL),
|
Update events to use Swagger 1.3 subtyping, and related aftermath
This patch started with the simple idea of changing the /events data
model to be more sane. The original model would send out events like:
{ "stasis_start": { "args": [], "channel": { ... } } }
The event discriminator was the field name instead of being a value in
the object, due to limitations in how Swagger 1.1 could model objects.
While technically sufficient in communicating event information, it was
really difficult to deal with in terms of client side JSON handling.
This patch takes advantage of a proposed extension[1] to Swagger which
allows type variance through the use of a discriminator field. This had
a domino effect that made this a surprisingly large patch.
[1]: https://groups.google.com/d/msg/wordnik-api/EC3rGajE0os/ey_5dBI_jWcJ
In changing the models, I also had to change the swagger_model.py
processor so it can handle the type discriminator and subtyping. I took
that a big step forward, and using that information to generate an
ari_model module, which can validate a JSON object against the Swagger
model.
The REST and WebSocket generators were changed to take advantage of the
validators. If compiled with AST_DEVMODE enabled, JSON objects that
don't match their corresponding models will not be sent out. For REST
API calls, a 500 Internal Server response is sent. For WebSockets, the
invalid JSON message is replaced with an error message.
Since this took over about half of the job of the existing JSON
generators, and the .to_json virtual function on messages took over the
other half, I reluctantly removed the generators.
The validators turned up all sorts of errors and inconsistencies in our
data models, and the code. These were cleaned up, with checks in the
code generator avoid some of the consistency problems in the future.
* The model for a channel snapshot was trimmed down to match the
information sent via AMI. Many of the field being sent were not
useful in the general case.
* The model for a bridge snapshot was updated to be more consistent
with the other ARI models.
Another impact of introducing subtyping was that the swagger-codegen
documentation generator was insufficient (at least until it catches up
with Swagger 1.2). I wanted it to be easier to generate docs for the API
anyways, so I ported the wiki pages to use the Asterisk Swagger
generator. In the process, I was able to clean up many of the model
links, which would occasionally give inconsistent results on the wiki. I
also added error responses to the wiki docs, making the wiki
documentation more complete.
Finally, since Stasis-HTTP will now be named Asterisk REST Interface
(ARI), any new functions and files I created carry the ari_ prefix. I
changed a few stasis_http references to ari where it was non-intrusive
and made sense.
(closes issue ASTERISK-21885)
Review: https://reviewboard.asterisk.org/r/2639/
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@393529 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-07-03 16:32:41 +00:00
|
|
|
"channel", ast_channel_snapshot_to_json(snapshot));
|
2013-05-14 21:45:08 +00:00
|
|
|
if (!msg) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
app_send(app, msg);
|
|
|
|
return 0;
|
|
|
|
}
|
2013-04-22 14:58:53 +00:00
|
|
|
|
2013-07-19 19:35:21 +00:00
|
|
|
void stasis_app_control_execute_until_exhausted(struct ast_channel *chan, struct stasis_app_control *control)
|
|
|
|
{
|
|
|
|
while (!control_is_done(control)) {
|
|
|
|
int command_count = control_dispatch_all(control, chan);
|
|
|
|
if (command_count == 0 || ast_channel_fdno(chan) == -1) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-15 16:43:47 +00:00
|
|
|
/*! /brief Stasis dialplan application callback */
|
|
|
|
int stasis_app_exec(struct ast_channel *chan, const char *app_name, int argc,
|
|
|
|
char *argv[])
|
|
|
|
{
|
2013-05-14 21:45:08 +00:00
|
|
|
SCOPED_MODULE_USE(ast_module_info->self);
|
|
|
|
|
2013-04-15 16:43:47 +00:00
|
|
|
RAII_VAR(struct app *, app, NULL, ao2_cleanup);
|
|
|
|
RAII_VAR(struct stasis_app_control *, control, NULL, control_unlink);
|
|
|
|
int res = 0;
|
|
|
|
|
|
|
|
ast_assert(chan != NULL);
|
|
|
|
|
2013-05-14 21:45:08 +00:00
|
|
|
app = ao2_find(apps_registry, app_name, OBJ_KEY);
|
2013-04-15 16:43:47 +00:00
|
|
|
if (!app) {
|
|
|
|
ast_log(LOG_ERROR,
|
|
|
|
"Stasis app '%s' not registered\n", app_name);
|
|
|
|
return -1;
|
|
|
|
}
|
2013-07-23 13:42:46 +00:00
|
|
|
if (!app_is_active(app)) {
|
|
|
|
ast_log(LOG_ERROR,
|
|
|
|
"Stasis app '%s' not active\n", app_name);
|
|
|
|
return -1;
|
|
|
|
}
|
2013-04-15 16:43:47 +00:00
|
|
|
|
2013-05-14 21:45:08 +00:00
|
|
|
control = control_create(chan);
|
|
|
|
if (!control) {
|
|
|
|
ast_log(LOG_ERROR, "Allocated failed\n");
|
|
|
|
return -1;
|
2013-04-15 16:43:47 +00:00
|
|
|
}
|
2013-05-14 21:45:08 +00:00
|
|
|
ao2_link(app_controls, control);
|
2013-04-15 16:43:47 +00:00
|
|
|
|
ARI: WebSocket event cleanup
Stasis events (which get distributed over the ARI WebSocket) are created
by subscribing to the channel_all_cached and bridge_all_cached topics,
filtering out events for channels/bridges currently subscribed to.
There are two issues with that. First was a race condition, where
messages in-flight to the master subscribe-to-all-things topic would get
sent out, even though the events happened before the channel was put
into Stasis. Secondly, as the number of channels and bridges grow in the
system, the work spent filtering messages becomes excessive.
Since r395954, individual channels and bridges have caching topics, and
can be subscribed to individually. This patch takes advantage, so that
channels and bridges are subscribed to on demand, instead of filtering
the global topics.
The one case where filtering is still required is handling BridgeMerge
messages, which are published directly to the bridge_all topic.
Other than the change to how subscriptions work, this patch mostly just
moves code around. Most of the work generating JSON objects from
messages was moved to .to_json handlers on the message types. The
callback functions handling app subscriptions were moved from res_stasis
(b/c they were global to the model) to stasis/app.c (b/c they are local
to the app now).
(closes issue ASTERISK-21969)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2754/
........
Merged revisions 397816 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397820 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-08-27 19:19:36 +00:00
|
|
|
res = send_start_msg(app, chan, argc, argv);
|
2013-04-15 16:43:47 +00:00
|
|
|
if (res != 0) {
|
2013-05-14 21:45:08 +00:00
|
|
|
ast_log(LOG_ERROR,
|
2013-07-23 13:42:46 +00:00
|
|
|
"Error sending start message to '%s'\n", app_name);
|
ARI: WebSocket event cleanup
Stasis events (which get distributed over the ARI WebSocket) are created
by subscribing to the channel_all_cached and bridge_all_cached topics,
filtering out events for channels/bridges currently subscribed to.
There are two issues with that. First was a race condition, where
messages in-flight to the master subscribe-to-all-things topic would get
sent out, even though the events happened before the channel was put
into Stasis. Secondly, as the number of channels and bridges grow in the
system, the work spent filtering messages becomes excessive.
Since r395954, individual channels and bridges have caching topics, and
can be subscribed to individually. This patch takes advantage, so that
channels and bridges are subscribed to on demand, instead of filtering
the global topics.
The one case where filtering is still required is handling BridgeMerge
messages, which are published directly to the bridge_all topic.
Other than the change to how subscriptions work, this patch mostly just
moves code around. Most of the work generating JSON objects from
messages was moved to .to_json handlers on the message types. The
callback functions handling app subscriptions were moved from res_stasis
(b/c they were global to the model) to stasis/app.c (b/c they are local
to the app now).
(closes issue ASTERISK-21969)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2754/
........
Merged revisions 397816 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397820 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-08-27 19:19:36 +00:00
|
|
|
return -1;
|
2013-04-15 16:43:47 +00:00
|
|
|
}
|
|
|
|
|
ARI: WebSocket event cleanup
Stasis events (which get distributed over the ARI WebSocket) are created
by subscribing to the channel_all_cached and bridge_all_cached topics,
filtering out events for channels/bridges currently subscribed to.
There are two issues with that. First was a race condition, where
messages in-flight to the master subscribe-to-all-things topic would get
sent out, even though the events happened before the channel was put
into Stasis. Secondly, as the number of channels and bridges grow in the
system, the work spent filtering messages becomes excessive.
Since r395954, individual channels and bridges have caching topics, and
can be subscribed to individually. This patch takes advantage, so that
channels and bridges are subscribed to on demand, instead of filtering
the global topics.
The one case where filtering is still required is handling BridgeMerge
messages, which are published directly to the bridge_all topic.
Other than the change to how subscriptions work, this patch mostly just
moves code around. Most of the work generating JSON objects from
messages was moved to .to_json handlers on the message types. The
callback functions handling app subscriptions were moved from res_stasis
(b/c they were global to the model) to stasis/app.c (b/c they are local
to the app now).
(closes issue ASTERISK-21969)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2754/
........
Merged revisions 397816 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397820 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-08-27 19:19:36 +00:00
|
|
|
res = app_subscribe_channel(app, chan);
|
|
|
|
if (res != 0) {
|
|
|
|
ast_log(LOG_ERROR, "Error subscribing app '%s' to channel '%s'\n",
|
|
|
|
app_name, ast_channel_name(chan));
|
2013-05-10 13:13:06 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-05-14 21:45:08 +00:00
|
|
|
while (!control_is_done(control)) {
|
2013-04-22 14:58:53 +00:00
|
|
|
RAII_VAR(struct ast_frame *, f, NULL, ast_frame_dtor);
|
|
|
|
int r;
|
2013-05-14 21:45:08 +00:00
|
|
|
int command_count;
|
ARI: WebSocket event cleanup
Stasis events (which get distributed over the ARI WebSocket) are created
by subscribing to the channel_all_cached and bridge_all_cached topics,
filtering out events for channels/bridges currently subscribed to.
There are two issues with that. First was a race condition, where
messages in-flight to the master subscribe-to-all-things topic would get
sent out, even though the events happened before the channel was put
into Stasis. Secondly, as the number of channels and bridges grow in the
system, the work spent filtering messages becomes excessive.
Since r395954, individual channels and bridges have caching topics, and
can be subscribed to individually. This patch takes advantage, so that
channels and bridges are subscribed to on demand, instead of filtering
the global topics.
The one case where filtering is still required is handling BridgeMerge
messages, which are published directly to the bridge_all topic.
Other than the change to how subscriptions work, this patch mostly just
moves code around. Most of the work generating JSON objects from
messages was moved to .to_json handlers on the message types. The
callback functions handling app subscriptions were moved from res_stasis
(b/c they were global to the model) to stasis/app.c (b/c they are local
to the app now).
(closes issue ASTERISK-21969)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2754/
........
Merged revisions 397816 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397820 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-08-27 19:19:36 +00:00
|
|
|
struct ast_bridge *last_bridge = NULL;
|
|
|
|
struct ast_bridge *bridge = NULL;
|
2013-04-22 14:58:53 +00:00
|
|
|
|
2013-08-21 14:08:23 +00:00
|
|
|
/* Check to see if a bridge absorbed our hangup frame */
|
|
|
|
if (ast_check_hangup_locked(chan)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
ARI: WebSocket event cleanup
Stasis events (which get distributed over the ARI WebSocket) are created
by subscribing to the channel_all_cached and bridge_all_cached topics,
filtering out events for channels/bridges currently subscribed to.
There are two issues with that. First was a race condition, where
messages in-flight to the master subscribe-to-all-things topic would get
sent out, even though the events happened before the channel was put
into Stasis. Secondly, as the number of channels and bridges grow in the
system, the work spent filtering messages becomes excessive.
Since r395954, individual channels and bridges have caching topics, and
can be subscribed to individually. This patch takes advantage, so that
channels and bridges are subscribed to on demand, instead of filtering
the global topics.
The one case where filtering is still required is handling BridgeMerge
messages, which are published directly to the bridge_all topic.
Other than the change to how subscriptions work, this patch mostly just
moves code around. Most of the work generating JSON objects from
messages was moved to .to_json handlers on the message types. The
callback functions handling app subscriptions were moved from res_stasis
(b/c they were global to the model) to stasis/app.c (b/c they are local
to the app now).
(closes issue ASTERISK-21969)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2754/
........
Merged revisions 397816 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397820 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-08-27 19:19:36 +00:00
|
|
|
last_bridge = bridge;
|
|
|
|
bridge = stasis_app_get_bridge(control);
|
|
|
|
|
|
|
|
if (bridge != last_bridge) {
|
|
|
|
app_unsubscribe_bridge(app, last_bridge);
|
|
|
|
app_subscribe_bridge(app, bridge);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bridge) {
|
2013-08-13 15:27:32 +00:00
|
|
|
/* Bridge is handling channel frames */
|
|
|
|
control_wait(control);
|
|
|
|
control_dispatch_all(control, chan);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2013-04-22 14:58:53 +00:00
|
|
|
r = ast_waitfor(chan, MAX_WAIT_MS);
|
|
|
|
|
|
|
|
if (r < 0) {
|
|
|
|
ast_debug(3, "%s: Poll error\n",
|
|
|
|
ast_channel_uniqueid(chan));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-05-14 21:45:08 +00:00
|
|
|
command_count = control_dispatch_all(control, chan);
|
|
|
|
|
|
|
|
if (command_count > 0 && ast_channel_fdno(chan) == -1) {
|
|
|
|
/* Command drained the channel; wait for next frame */
|
|
|
|
continue;
|
|
|
|
}
|
2013-04-22 14:58:53 +00:00
|
|
|
|
|
|
|
if (r == 0) {
|
|
|
|
/* Timeout */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
f = ast_read(chan);
|
2013-04-15 16:43:47 +00:00
|
|
|
if (!f) {
|
2013-08-21 16:00:10 +00:00
|
|
|
/* Continue on in the dialplan */
|
|
|
|
ast_debug(3, "%s: Hangup (no more frames)\n",
|
2013-05-14 21:45:08 +00:00
|
|
|
ast_channel_uniqueid(chan));
|
2013-04-15 16:43:47 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-08-21 16:00:10 +00:00
|
|
|
if (f->frametype == AST_FRAME_CONTROL) {
|
2013-04-15 16:43:47 +00:00
|
|
|
if (f->subclass.integer == AST_CONTROL_HANGUP) {
|
2013-05-14 21:45:08 +00:00
|
|
|
/* Continue on in the dialplan */
|
|
|
|
ast_debug(3, "%s: Hangup\n",
|
|
|
|
ast_channel_uniqueid(chan));
|
2013-08-21 16:00:10 +00:00
|
|
|
break;
|
2013-04-15 16:43:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
ARI: WebSocket event cleanup
Stasis events (which get distributed over the ARI WebSocket) are created
by subscribing to the channel_all_cached and bridge_all_cached topics,
filtering out events for channels/bridges currently subscribed to.
There are two issues with that. First was a race condition, where
messages in-flight to the master subscribe-to-all-things topic would get
sent out, even though the events happened before the channel was put
into Stasis. Secondly, as the number of channels and bridges grow in the
system, the work spent filtering messages becomes excessive.
Since r395954, individual channels and bridges have caching topics, and
can be subscribed to individually. This patch takes advantage, so that
channels and bridges are subscribed to on demand, instead of filtering
the global topics.
The one case where filtering is still required is handling BridgeMerge
messages, which are published directly to the bridge_all topic.
Other than the change to how subscriptions work, this patch mostly just
moves code around. Most of the work generating JSON objects from
messages was moved to .to_json handlers on the message types. The
callback functions handling app subscriptions were moved from res_stasis
(b/c they were global to the model) to stasis/app.c (b/c they are local
to the app now).
(closes issue ASTERISK-21969)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2754/
........
Merged revisions 397816 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397820 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-08-27 19:19:36 +00:00
|
|
|
app_unsubscribe_bridge(app, stasis_app_get_bridge(control));
|
|
|
|
app_unsubscribe_channel(app, chan);
|
|
|
|
|
|
|
|
res = send_end_msg(app, chan);
|
2013-04-15 16:43:47 +00:00
|
|
|
if (res != 0) {
|
|
|
|
ast_log(LOG_ERROR,
|
|
|
|
"Error sending end message to %s\n", app_name);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
ARI: WebSocket event cleanup
Stasis events (which get distributed over the ARI WebSocket) are created
by subscribing to the channel_all_cached and bridge_all_cached topics,
filtering out events for channels/bridges currently subscribed to.
There are two issues with that. First was a race condition, where
messages in-flight to the master subscribe-to-all-things topic would get
sent out, even though the events happened before the channel was put
into Stasis. Secondly, as the number of channels and bridges grow in the
system, the work spent filtering messages becomes excessive.
Since r395954, individual channels and bridges have caching topics, and
can be subscribed to individually. This patch takes advantage, so that
channels and bridges are subscribed to on demand, instead of filtering
the global topics.
The one case where filtering is still required is handling BridgeMerge
messages, which are published directly to the bridge_all topic.
Other than the change to how subscriptions work, this patch mostly just
moves code around. Most of the work generating JSON objects from
messages was moved to .to_json handlers on the message types. The
callback functions handling app subscriptions were moved from res_stasis
(b/c they were global to the model) to stasis/app.c (b/c they are local
to the app now).
(closes issue ASTERISK-21969)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2754/
........
Merged revisions 397816 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397820 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-08-27 19:19:36 +00:00
|
|
|
/* There's an off chance that app is ready for cleanup. Go ahead
|
|
|
|
* and clean up, just in case
|
|
|
|
*/
|
|
|
|
cleanup();
|
|
|
|
|
2013-04-15 16:43:47 +00:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
int stasis_app_send(const char *app_name, struct ast_json *message)
|
|
|
|
{
|
|
|
|
RAII_VAR(struct app *, app, NULL, ao2_cleanup);
|
|
|
|
|
2013-05-14 21:45:08 +00:00
|
|
|
app = ao2_find(apps_registry, app_name, OBJ_KEY);
|
2013-04-15 16:43:47 +00:00
|
|
|
|
|
|
|
if (!app) {
|
|
|
|
/* XXX We can do a better job handling late binding, queueing up
|
|
|
|
* the call for a few seconds to wait for the app to register.
|
|
|
|
*/
|
|
|
|
ast_log(LOG_WARNING,
|
|
|
|
"Stasis app '%s' not registered\n", app_name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
app_send(app, message);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int stasis_app_register(const char *app_name, stasis_app_cb handler, void *data)
|
|
|
|
{
|
|
|
|
RAII_VAR(struct app *, app, NULL, ao2_cleanup);
|
|
|
|
|
2013-05-14 21:45:08 +00:00
|
|
|
SCOPED_LOCK(apps_lock, apps_registry, ao2_lock, ao2_unlock);
|
2013-04-15 16:43:47 +00:00
|
|
|
|
2013-05-14 21:45:08 +00:00
|
|
|
app = ao2_find(apps_registry, app_name, OBJ_KEY | OBJ_NOLOCK);
|
2013-04-15 16:43:47 +00:00
|
|
|
|
|
|
|
if (app) {
|
2013-05-14 21:45:08 +00:00
|
|
|
app_update(app, handler, data);
|
2013-04-15 16:43:47 +00:00
|
|
|
} else {
|
|
|
|
app = app_create(app_name, handler, data);
|
|
|
|
if (app) {
|
2013-05-14 21:45:08 +00:00
|
|
|
ao2_link_flags(apps_registry, app, OBJ_NOLOCK);
|
2013-04-15 16:43:47 +00:00
|
|
|
} else {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-23 13:42:46 +00:00
|
|
|
/* We lazily clean up the apps_registry, because it's good enough to
|
|
|
|
* prevent memory leaks, and we're lazy.
|
|
|
|
*/
|
|
|
|
cleanup();
|
2013-04-15 16:43:47 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void stasis_app_unregister(const char *app_name)
|
|
|
|
{
|
2013-07-23 13:42:46 +00:00
|
|
|
RAII_VAR(struct app *, app, NULL, ao2_cleanup);
|
|
|
|
|
|
|
|
if (!app_name) {
|
|
|
|
return;
|
2013-04-15 16:43:47 +00:00
|
|
|
}
|
2013-07-23 13:42:46 +00:00
|
|
|
|
|
|
|
app = ao2_find(apps_registry, app_name, OBJ_KEY);
|
|
|
|
if (!app) {
|
|
|
|
ast_log(LOG_ERROR,
|
|
|
|
"Stasis app '%s' not registered\n", app_name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
app_deactivate(app);
|
|
|
|
|
|
|
|
/* There's a decent chance that app is ready for cleanup. Go ahead
|
|
|
|
* and clean up, just in case
|
|
|
|
*/
|
|
|
|
cleanup();
|
2013-04-15 16:43:47 +00:00
|
|
|
}
|
|
|
|
|
2013-05-10 17:12:57 +00:00
|
|
|
void stasis_app_ref(void)
|
|
|
|
{
|
|
|
|
ast_module_ref(ast_module_info->self);
|
|
|
|
}
|
|
|
|
|
|
|
|
void stasis_app_unref(void)
|
|
|
|
{
|
|
|
|
ast_module_unref(ast_module_info->self);
|
|
|
|
}
|
|
|
|
|
2013-04-15 16:43:47 +00:00
|
|
|
static int load_module(void)
|
|
|
|
{
|
ARI: WebSocket event cleanup
Stasis events (which get distributed over the ARI WebSocket) are created
by subscribing to the channel_all_cached and bridge_all_cached topics,
filtering out events for channels/bridges currently subscribed to.
There are two issues with that. First was a race condition, where
messages in-flight to the master subscribe-to-all-things topic would get
sent out, even though the events happened before the channel was put
into Stasis. Secondly, as the number of channels and bridges grow in the
system, the work spent filtering messages becomes excessive.
Since r395954, individual channels and bridges have caching topics, and
can be subscribed to individually. This patch takes advantage, so that
channels and bridges are subscribed to on demand, instead of filtering
the global topics.
The one case where filtering is still required is handling BridgeMerge
messages, which are published directly to the bridge_all topic.
Other than the change to how subscriptions work, this patch mostly just
moves code around. Most of the work generating JSON objects from
messages was moved to .to_json handlers on the message types. The
callback functions handling app subscriptions were moved from res_stasis
(b/c they were global to the model) to stasis/app.c (b/c they are local
to the app now).
(closes issue ASTERISK-21969)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2754/
........
Merged revisions 397816 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397820 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-08-27 19:19:36 +00:00
|
|
|
apps_registry = ao2_container_alloc(APPS_NUM_BUCKETS, app_hash,
|
|
|
|
app_compare);
|
2013-05-14 21:45:08 +00:00
|
|
|
if (apps_registry == NULL) {
|
2013-04-15 16:43:47 +00:00
|
|
|
return AST_MODULE_LOAD_FAILURE;
|
|
|
|
}
|
|
|
|
|
ARI: WebSocket event cleanup
Stasis events (which get distributed over the ARI WebSocket) are created
by subscribing to the channel_all_cached and bridge_all_cached topics,
filtering out events for channels/bridges currently subscribed to.
There are two issues with that. First was a race condition, where
messages in-flight to the master subscribe-to-all-things topic would get
sent out, even though the events happened before the channel was put
into Stasis. Secondly, as the number of channels and bridges grow in the
system, the work spent filtering messages becomes excessive.
Since r395954, individual channels and bridges have caching topics, and
can be subscribed to individually. This patch takes advantage, so that
channels and bridges are subscribed to on demand, instead of filtering
the global topics.
The one case where filtering is still required is handling BridgeMerge
messages, which are published directly to the bridge_all topic.
Other than the change to how subscriptions work, this patch mostly just
moves code around. Most of the work generating JSON objects from
messages was moved to .to_json handlers on the message types. The
callback functions handling app subscriptions were moved from res_stasis
(b/c they were global to the model) to stasis/app.c (b/c they are local
to the app now).
(closes issue ASTERISK-21969)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2754/
........
Merged revisions 397816 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397820 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-08-27 19:19:36 +00:00
|
|
|
app_controls = ao2_container_alloc(CONTROLS_NUM_BUCKETS, control_hash,
|
|
|
|
control_compare);
|
2013-05-14 21:45:08 +00:00
|
|
|
if (app_controls == NULL) {
|
2013-04-15 16:43:47 +00:00
|
|
|
return AST_MODULE_LOAD_FAILURE;
|
|
|
|
}
|
|
|
|
|
ARI: WebSocket event cleanup
Stasis events (which get distributed over the ARI WebSocket) are created
by subscribing to the channel_all_cached and bridge_all_cached topics,
filtering out events for channels/bridges currently subscribed to.
There are two issues with that. First was a race condition, where
messages in-flight to the master subscribe-to-all-things topic would get
sent out, even though the events happened before the channel was put
into Stasis. Secondly, as the number of channels and bridges grow in the
system, the work spent filtering messages becomes excessive.
Since r395954, individual channels and bridges have caching topics, and
can be subscribed to individually. This patch takes advantage, so that
channels and bridges are subscribed to on demand, instead of filtering
the global topics.
The one case where filtering is still required is handling BridgeMerge
messages, which are published directly to the bridge_all topic.
Other than the change to how subscriptions work, this patch mostly just
moves code around. Most of the work generating JSON objects from
messages was moved to .to_json handlers on the message types. The
callback functions handling app subscriptions were moved from res_stasis
(b/c they were global to the model) to stasis/app.c (b/c they are local
to the app now).
(closes issue ASTERISK-21969)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2754/
........
Merged revisions 397816 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397820 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-08-27 19:19:36 +00:00
|
|
|
app_bridges = ao2_container_alloc(BRIDGES_NUM_BUCKETS, bridges_hash,
|
|
|
|
bridges_compare);
|
2013-06-10 13:07:11 +00:00
|
|
|
|
2013-08-23 00:26:19 +00:00
|
|
|
app_bridges_moh = ao2_container_alloc_hash(
|
|
|
|
AO2_ALLOC_OPT_LOCK_MUTEX, AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT,
|
|
|
|
37, bridges_moh_hash_fn, bridges_moh_sort_fn, NULL);
|
|
|
|
|
|
|
|
if (!app_bridges_moh) {
|
|
|
|
return AST_MODULE_LOAD_FAILURE;
|
|
|
|
}
|
|
|
|
|
2013-05-10 13:13:06 +00:00
|
|
|
return AST_MODULE_LOAD_SUCCESS;
|
2013-04-15 16:43:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int unload_module(void)
|
|
|
|
{
|
2013-05-14 21:45:08 +00:00
|
|
|
ao2_cleanup(apps_registry);
|
|
|
|
apps_registry = NULL;
|
2013-04-15 16:43:47 +00:00
|
|
|
|
2013-05-14 21:45:08 +00:00
|
|
|
ao2_cleanup(app_controls);
|
|
|
|
app_controls = NULL;
|
2013-04-15 16:43:47 +00:00
|
|
|
|
2013-06-10 13:07:11 +00:00
|
|
|
ao2_cleanup(app_bridges);
|
|
|
|
app_bridges = NULL;
|
|
|
|
|
2013-08-23 00:26:19 +00:00
|
|
|
ao2_cleanup(app_bridges_moh);
|
|
|
|
app_bridges_moh = NULL;
|
|
|
|
|
ARI: WebSocket event cleanup
Stasis events (which get distributed over the ARI WebSocket) are created
by subscribing to the channel_all_cached and bridge_all_cached topics,
filtering out events for channels/bridges currently subscribed to.
There are two issues with that. First was a race condition, where
messages in-flight to the master subscribe-to-all-things topic would get
sent out, even though the events happened before the channel was put
into Stasis. Secondly, as the number of channels and bridges grow in the
system, the work spent filtering messages becomes excessive.
Since r395954, individual channels and bridges have caching topics, and
can be subscribed to individually. This patch takes advantage, so that
channels and bridges are subscribed to on demand, instead of filtering
the global topics.
The one case where filtering is still required is handling BridgeMerge
messages, which are published directly to the bridge_all topic.
Other than the change to how subscriptions work, this patch mostly just
moves code around. Most of the work generating JSON objects from
messages was moved to .to_json handlers on the message types. The
callback functions handling app subscriptions were moved from res_stasis
(b/c they were global to the model) to stasis/app.c (b/c they are local
to the app now).
(closes issue ASTERISK-21969)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2754/
........
Merged revisions 397816 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397820 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2013-08-27 19:19:36 +00:00
|
|
|
return 0;
|
2013-04-15 16:43:47 +00:00
|
|
|
}
|
|
|
|
|
2013-06-24 21:40:52 +00:00
|
|
|
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Stasis application support",
|
|
|
|
.load = load_module,
|
|
|
|
.unload = unload_module,
|
|
|
|
);
|