[svn-commits] dlee: branch dlee/stasis-http r380648 - in /team/dlee/stasis-http: include/as...
SVN commits to the Digium repositories
svn-commits at lists.digium.com
Thu Jan 31 11:05:44 CST 2013
Author: dlee
Date: Thu Jan 31 11:05:40 2013
New Revision: 380648
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=380648
Log:
Application registration
Added:
team/dlee/stasis-http/tests/test_stasis_core.c (with props)
Modified:
team/dlee/stasis-http/include/asterisk/stasis.h
team/dlee/stasis-http/res/res_stasis_core.c
Modified: team/dlee/stasis-http/include/asterisk/stasis.h
URL: http://svnview.digium.com/svn/asterisk/team/dlee/stasis-http/include/asterisk/stasis.h?view=diff&rev=380648&r1=380647&r2=380648
==============================================================================
--- team/dlee/stasis-http/include/asterisk/stasis.h (original)
+++ team/dlee/stasis-http/include/asterisk/stasis.h Thu Jan 31 11:05:40 2013
@@ -34,12 +34,38 @@
* \param chan Channel to invoke application upon
* \param argc Number of arguments to pass into the application
* \param argv Argument array.
- * \return 0 for success; -1 for error.
+ * \return 0 for success.
+ * \return -1 for error.
*/
int stasis_app_invoke(const char *app_name, struct ast_channel *chan, int argc, char *argv[]);
+/*!
+ * \brief Callback for Stasis application handler.
+ *
+ * The message given to the handler is a borrowed copy. If you want to keep a
+ * reference to it, you should use \c ast_ref() to keep it around.
+ *
+ * \param data Data ptr given when registered
+ * \param message Message to handle. (borrowed copy)
+ */
typedef void (*stasis_app_handler)(void *data, struct ast_json *message);
+/*!
+ * \brief Register a new Stasis application.
+ * If an application is already registered with the given name, the old
+ * application is sent a 'replaced' message and unregistered.
+ * \param app_name Name of this application.
+ * \param handler Callback for application messages.
+ * \param data Data blob to pass to the callback.
+ * \return 0 for success
+ * \return -1 for error.
+ */
int stasis_app_register(const char *app_name, stasis_app_handler handler, void *data);
+/*!
+ * \brief Unregister a Stasis application.
+ * \param app_name Name of the application to unregister.
+ */
+void stasis_app_unregister(const char *app_name);
+
#endif /* _ASTERISK_STASIS_H */
Modified: team/dlee/stasis-http/res/res_stasis_core.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/stasis-http/res/res_stasis_core.c?view=diff&rev=380648&r1=380647&r2=380648
==============================================================================
--- team/dlee/stasis-http/res/res_stasis_core.c (original)
+++ team/dlee/stasis-http/res/res_stasis_core.c Thu Jan 31 11:05:40 2013
@@ -44,13 +44,20 @@
/*! Stasis application ref */
struct stasis_app {
- const char *name;
+ char *name;
stasis_app_handler handler;
void *data;
};
/*! Stasis application container */
-struct ao2_container *stasis_apps;
+struct ao2_container *__stasis_apps;
+
+static struct ao2_container *stasis_apps(void)
+{
+ ao2_ref(__stasis_apps, 1);
+ return __stasis_apps;
+}
+
/*! Hash function for stasis_app */
static int hash_app(const void *obj, const int flags)
@@ -75,30 +82,33 @@
}
}
-static void app_dtor(void *app)
+static void app_dtor(void *obj)
{
- /* No-op */
+ struct stasis_app *app = obj;
+ ast_free(app->name);
}
int stasis_app_invoke(const char *app_name, struct ast_channel *chan, int argc, char *argv[])
{
- RAII_VAR(struct ao2_container *, apps, stasis_apps, ao2_cleanup);
+ RAII_VAR(struct ao2_container *, apps, stasis_apps(), ao2_cleanup);
RAII_VAR(struct stasis_app *, app, NULL, ao2_cleanup);
RAII_VAR(struct ast_json *, msg, NULL, ast_json_unref);
struct ast_json *json_args;
int i;
- ao2_ref(apps, 1);
app = ao2_find(apps, app_name, OBJ_KEY);
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;
}
- msg = ast_json_pack("{s: s, s: s, s: []}",
+ msg = ast_json_pack("{s: s, s: o, s: []}",
"command", "invoke",
- "channel", ast_channel_name(chan),
+ "channel", chan ? ast_json_string_create(ast_channel_name(chan)) : ast_json_null(),
"args");
if (!msg) {
ast_log(LOG_ERROR, "Couldn't create message for %s\n", app_name);
@@ -117,36 +127,46 @@
int stasis_app_register(const char *app_name, stasis_app_handler handler, void *data)
{
- RAII_VAR(struct ao2_container *, apps, stasis_apps, ao2_cleanup);
+ RAII_VAR(struct ao2_container *, apps, stasis_apps(), ao2_cleanup);
+ RAII_VAR(struct stasis_app *, app, NULL, ao2_cleanup);
- ao2_ref(apps, 1);
- {
- RAII_VAR(struct stasis_app *, app, ao2_find(apps, app_name, OBJ_KEY | OBJ_NOLOCK), ao2_cleanup);
- SCOPED_LOCK(apps_lock, apps, ao2_lock, ao2_unlock);
+ SCOPED_LOCK(apps_lock, apps, ao2_lock, ao2_unlock);
+ app = ao2_find(apps, app_name, OBJ_KEY | OBJ_NOLOCK);
+
+ if (app) {
+ RAII_VAR(struct ast_json *, msg, NULL, ast_json_unref);
+ msg = ast_json_pack("{s: s}", "event", "replaced");
+ app->handler(app->data, msg);
+ } else {
+ app = ao2_alloc(sizeof(*app), app_dtor);
+ app->name = ast_strdup(app_name);
if (app) {
- RAII_VAR(struct ast_json *, msg, NULL, ast_json_unref);
- msg = ast_json_pack("{s: s}", "event", "replaced");
- app->handler(app->data, msg);
+ ao2_link(apps, app);
} else {
- app = ao2_alloc(sizeof(*app), app_dtor);
- }
-
- if (!app) {
ast_log(LOG_ERROR, "Failed to allocate stasis_app\n");
return -1;
}
+ }
- app->handler = handler;
- app->data = data;
- }
+ app->handler = handler;
+ app->data = data;
+
return 0;
}
+void stasis_app_unregister(const char *app_name)
+{
+ RAII_VAR(struct ao2_container *, apps, stasis_apps(), ao2_cleanup);
+
+ ao2_cleanup(ao2_find(apps, app_name, OBJ_KEY | OBJ_UNLINK));
+}
+
+
static int load_module(void)
{
- stasis_apps = ao2_container_alloc(APPS_NUM_BUCKETS, hash_app, compare_app);
- if (stasis_apps == NULL) {
+ __stasis_apps = ao2_container_alloc(APPS_NUM_BUCKETS, hash_app, compare_app);
+ if (__stasis_apps == NULL) {
return AST_MODULE_LOAD_FAILURE;
}
return AST_MODULE_LOAD_SUCCESS;
@@ -154,8 +174,8 @@
static int unload_module(void)
{
- ao2_ref(stasis_apps, -1);
- stasis_apps = 0;
+ ao2_ref(__stasis_apps, -1);
+ __stasis_apps = NULL;
return 0;
}
Added: team/dlee/stasis-http/tests/test_stasis_core.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/stasis-http/tests/test_stasis_core.c?view=auto&rev=380648
==============================================================================
--- team/dlee/stasis-http/tests/test_stasis_core.c (added)
+++ team/dlee/stasis-http/tests/test_stasis_core.c Thu Jan 31 11:05:40 2013
@@ -1,0 +1,144 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * David M. Lee, II <dlee at 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 Test Stasis Core API.
+ * \author\verbatim David M. Lee, II <dlee at digium.com> \endverbatim
+ *
+ * \ingroup tests
+ */
+
+/*** MODULEINFO
+ <depend>TEST_FRAMEWORK</depend>
+ <depend>res_stasis_core</depend>
+ <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/module.h"
+#include "asterisk/test.h"
+#include "asterisk/stasis.h"
+
+AST_TEST_DEFINE(app_invoke_dne)
+{
+ int res;
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = __func__;
+ info->category = "/stasis/core/";
+ info->summary = "Test stasis app invocation.";
+ info->description = "Test stasis app invocation.";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ res = stasis_app_invoke("i-am-not-an-app", NULL, 0, NULL);
+ ast_test_validate(test, -1 == res);
+
+ return AST_TEST_PASS;
+}
+
+struct app_data {
+ int invocations;
+ struct ast_json *messages;
+};
+
+static struct app_data *app_data_create(void)
+{
+ struct app_data *res = ast_calloc(1, sizeof(struct app_data));
+ res->messages = ast_json_array_create();
+ return res;
+}
+
+static void app_data_dtor(struct app_data *actual)
+{
+ if (actual) {
+ ast_json_unref(actual->messages);
+ actual->messages = NULL;
+ ast_free(actual);
+ }
+}
+
+static void test_handler(void *data, struct ast_json *message)
+{
+ struct app_data *actual = data;
+ int res;
+ ++(actual->invocations);
+ res = ast_json_array_append(actual->messages, ast_json_copy(message));
+ ast_assert(res == 0);
+}
+
+AST_TEST_DEFINE(app_invoke_one)
+{
+ RAII_VAR(struct app_data *, app_data, NULL, app_data_dtor);
+ RAII_VAR(char *, app_name, "test-handler", stasis_app_unregister);
+ RAII_VAR(struct ast_json *, expected_message, NULL, ast_json_unref);
+ int res;
+
+
+ switch (cmd) {
+ case TEST_INIT:
+ info->name = __func__;
+ info->category = "/stasis/core/";
+ info->summary = "Test stasis app invocation.";
+ info->description = "Test stasis app invocation.";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ app_data = app_data_create();
+
+ stasis_app_register(app_name, test_handler, app_data);
+ expected_message = ast_json_pack("[{s: s, s: o, s: []}]",
+ "command", "invoke",
+ "channel", ast_json_null(),
+ "args");
+
+ res = stasis_app_invoke(app_name, NULL, 0, NULL);
+ ast_test_validate(test, 0 == res);
+ ast_test_validate(test, 1 == app_data->invocations);
+ ast_test_validate(test, ast_json_equal(expected_message, app_data->messages));
+
+ return AST_TEST_PASS;
+}
+
+static int unload_module(void)
+{
+ AST_TEST_UNREGISTER(app_invoke_dne);
+ AST_TEST_UNREGISTER(app_invoke_one);
+ return 0;
+}
+
+static int load_module(void)
+{
+ AST_TEST_REGISTER(app_invoke_one);
+ AST_TEST_REGISTER(app_invoke_dne);
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Stasis Core testing",
+ .load = load_module,
+ .unload = unload_module,
+ .nonoptreq = "res_stasis_core"
+ );
Propchange: team/dlee/stasis-http/tests/test_stasis_core.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/dlee/stasis-http/tests/test_stasis_core.c
------------------------------------------------------------------------------
svn:keywords = Author Date Id Rev URL
Propchange: team/dlee/stasis-http/tests/test_stasis_core.c
------------------------------------------------------------------------------
svn:mime-type = text/plain
More information about the svn-commits
mailing list