<p>Joshua Colp <strong>merged</strong> this change.</p><p><a href="https://gerrit.asterisk.org/6841">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Joshua Colp: Looks good to me, approved; Approved for Submit

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">This patch adds a beanstalk CEL backend.<br><br>Beanstalkd is a simple to use job queue. It provides a means to<br>create multiple job queues called "tubes". Each tube can store<br>multiple jobs, with varying priorities with the queue. Queue<br>processing is available via a simple TCP socket or via well defined<br>libraries, avaialble at<br>https://github.com/kr/beanstalkd/wiki/client-libraries<br><br>This module is based upon the beanstalk-client library, available<br>for download at: https://github.com/deepfryed/beanstalk-client<br><br>This module currently doesn't support user defined events.<br><br>Change-Id: Ic3a087faeeac045d69a2a018e60e29831ddb95ab<br>---<br>A cel/cel_beanstalkd.c<br>A configs/samples/cel_beanstalkd.conf.sample<br>2 files changed, 296 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">diff --git a/cel/cel_beanstalkd.c b/cel/cel_beanstalkd.c<br>new file mode 100644<br>index 0000000..e6f2380<br>--- /dev/null<br>+++ b/cel/cel_beanstalkd.c<br>@@ -0,0 +1,275 @@<br>+/*<br>+ * Asterisk -- An open source telephony toolkit.<br>+ *<br>+ * Copyright (C) 2017, Greenfield Technologies Ltd.<br>+ *<br>+ * Nir Simionovich <nirs@greenfieldtech.net><br>+ * who freely borrowed code from the cel manager equivalents<br>+ *     (see cel/cel_manager.c)<br>+ *<br>+ * See http://www.asterisk.org for more information about<br>+ * the Asterisk project. Please do not directly contact<br>+ * any of the maintainers of this project for assistance;<br>+ * the project provides a web site, mailing lists and IRC<br>+ * channels for your use.<br>+ *<br>+ * This program is free software, distributed under the terms of<br>+ * the GNU General Public License Version 2. See the LICENSE file<br>+ * at the top of the source tree.<br>+ */<br>+<br>+/*! \file<br>+ *<br>+ * \brief Asterisk Channel Event Beanstalkd backend<br>+ *<br>+ * This module requires the beanstalk-client library, avaialble from<br>+ * https://github.com/deepfryed/beanstalk-client<br>+ *<br>+ * See also<br>+ * \arg \ref AstCEL<br>+ * \ingroup cel_drivers<br>+ */<br>+<br>+/*! \li \ref cek_beanstalkd.c uses the configuration file \ref cel.conf<br>+ * \addtogroup configuration_file Configuration Files<br>+ */<br>+<br>+/*!<br>+ * \page cel.conf cel.conf<br>+ * \verbinclude cel.conf.sample<br>+ */<br>+<br>+/*** MODULEINFO<br>+        <depend>beanstalk</depend><br>+       <support_level>extended</support_level><br>+ ***/<br>+<br>+#include "asterisk.h"<br>+<br>+#include "asterisk/channel.h"<br>+#include "asterisk/cel.h"<br>+#include "asterisk/module.h"<br>+#include "asterisk/logger.h"<br>+#include "asterisk/utils.h"<br>+#include "asterisk/manager.h"<br>+#include "asterisk/config.h"<br>+#include "asterisk/json.h"<br>+<br>+#include "beanstalk.h"<br>+<br>+static const char DATE_FORMAT[] = "%Y-%m-%d %T";<br>+<br>+static const char CONF_FILE[] = "cel_beanstalkd.conf";<br>+<br>+/*! \brief Beanstalk CEL is off by default */<br>+#define CEL_BEANSTALK_ENABLED_DEFAULT          0<br>+<br>+static int enablecel;<br>+<br>+/*! \brief show_user_def is off by default */<br>+#define CEL_SHOW_USERDEF_DEFAULT      0<br>+<br>+#define CEL_BACKEND_NAME "Beanstalk Event Logging"<br>+<br>+#define BEANSTALK_JOB_SIZE 4096<br>+#define BEANSTALK_JOB_PRIORITY 99<br>+#define BEANSTALK_JOB_TTR 60<br>+#define BEANSTALK_JOB_DELAY 0<br>+#define DEFAULT_BEANSTALK_HOST "127.0.0.1"<br>+#define DEFAULT_BEANSTALK_PORT 11300<br>+#define DEFAULT_BEANSTALK_TUBE "asterisk-cel"<br>+<br>+static char *bs_host;<br>+static int bs_port;<br>+static char *bs_tube;<br>+static int priority;<br>+<br>+AST_RWLOCK_DEFINE_STATIC(config_lock);<br>+<br>+static void cel_bs_put(struct ast_event *event)<br>+{<br>+     struct ast_tm timeresult;<br>+    char start_time[80];<br>+ char *cel_buffer;<br>+    int bs_id;<br>+   int bs_socket;<br>+       struct ast_json *t_cel_json;<br>+<br>+      struct ast_cel_event_record record = {<br>+               .version = AST_CEL_EVENT_RECORD_VERSION,<br>+     };<br>+<br>+        if (!enablecel) {<br>+            return;<br>+      }<br>+<br>+ if (ast_cel_fill_record(event, &record)) {<br>+               return;<br>+      }<br>+<br>+ ast_rwlock_rdlock(&config_lock);<br>+ bs_socket = bs_connect(bs_host, bs_port);<br>+<br>+ if (bs_use(bs_socket, bs_tube) != BS_STATUS_OK) {<br>+            ast_log(LOG_ERROR, "Connection to Beanstalk tube %s @ %s:%d had failed", bs_tube, bs_host, bs_port);<br>+               ast_rwlock_unlock(&config_lock);<br>+         return;<br>+      }<br>+<br>+ ast_localtime(&record.event_time, &timeresult, NULL);<br>+        ast_strftime(start_time, sizeof(start_time), DATE_FORMAT, &timeresult);<br>+<br>+       ast_rwlock_unlock(&config_lock);<br>+<br>+      t_cel_json = ast_json_pack("{s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s, s:s}",<br>+                                                    "EventName", S_OR(record.event_name, ""),<br>+                                                        "AccountCode", S_OR(record.account_code, ""),<br>+                                                    "CallerIDnum", S_OR(record.caller_id_num, ""),<br>+                                                           "CallerIDname", S_OR(record.caller_id_name, ""),<br>+                                                         "CallerIDani", S_OR(record.caller_id_ani, ""),<br>+                                                           "CallerIDrdnis", S_OR(record.caller_id_rdnis, ""),<br>+                                                       "CallerIDdnid", S_OR(record.caller_id_dnid, ""),<br>+                                                         "Exten", S_OR(record.extension, ""),<br>+                                                     "Context", S_OR(record.context, ""),<br>+                                                     "Channel", S_OR(record.channel_name, ""),<br>+                                                        "Application", S_OR(record.application_name, ""),<br>+                                                        "AppData", S_OR(record.application_data, ""),<br>+                                                    "EventTime", S_OR(start_time, ""),<br>+                                                       "AMAFlags", S_OR(ast_channel_amaflags2string(record.amaflag), ""),<br>+                                                       "UniqueID", S_OR(record.unique_id, ""),<br>+                                                          "LinkedID", S_OR(record.linked_id, ""),<br>+                                                          "Userfield", S_OR(record.user_field, ""),<br>+                                                        "Peer", S_OR(record.peer_account, ""),<br>+                                                           "PeerAccount", S_OR(record.peer_account, ""),<br>+                                                    "Extra", S_OR(record.extra, "")<br>+<br>+    );<br>+<br>+        cel_buffer = ast_json_dump_string(t_cel_json);<br>+<br>+    ast_json_unref(t_cel_json);<br>+<br>+       bs_id = bs_put(bs_socket, priority, BEANSTALK_JOB_DELAY, BEANSTALK_JOB_TTR, cel_buffer, strlen(cel_buffer));<br>+<br>+      if (bs_id > 0) {<br>+          ast_log(LOG_DEBUG, "Successfully created job %d with %s\n", bs_id, cel_buffer);<br>+    } else {<br>+             ast_log(LOG_ERROR, "CDR job creation failed for %s\n", cel_buffer);<br>+        }<br>+<br>+ bs_disconnect(bs_socket);<br>+    ast_json_free(cel_buffer);<br>+}<br>+<br>+static int load_config(int reload)<br>+{<br>+   const char *cat = NULL;<br>+      struct ast_config *cfg;<br>+      struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };<br>+  struct ast_variable *v;<br>+      int newenablecel = CEL_BEANSTALK_ENABLED_DEFAULT;<br>+<br>+ cfg = ast_config_load(CONF_FILE, config_flags);<br>+      if (cfg == CONFIG_STATUS_FILEUNCHANGED) {<br>+            return 0;<br>+    }<br>+<br>+ if (cfg == CONFIG_STATUS_FILEINVALID) {<br>+              ast_log(LOG_WARNING, "Configuration file '%s' is invalid. CEL Beanstalkd Module not activated.\n",<br>+                 CONF_FILE);<br>+          return -1;<br>+   } else if (!cfg) {<br>+           ast_log(LOG_WARNING, "Failed to load configuration file. CEL Beanstalkd Module not activated.\n");<br>+         if (enablecel) {<br>+                     ast_cel_backend_unregister(CEL_BACKEND_NAME);<br>+                }<br>+            enablecel = 0;<br>+               return -1;<br>+   }<br>+<br>+ if (reload) {<br>+                ast_rwlock_wrlock(&config_lock);<br>+         ast_free(bs_host);<br>+           ast_free(bs_tube);<br>+   }<br>+<br>+ /* Bootstrap the default configuration */<br>+    bs_host = ast_strdup(DEFAULT_BEANSTALK_HOST);<br>+        bs_port = DEFAULT_BEANSTALK_PORT;<br>+    bs_tube = ast_strdup(DEFAULT_BEANSTALK_TUBE);<br>+        priority = BEANSTALK_JOB_PRIORITY;<br>+<br>+        while ((cat = ast_category_browse(cfg, cat))) {<br>+<br>+           if (strcasecmp(cat, "general")) {<br>+                  continue;<br>+            }<br>+<br>+         for (v = ast_variable_browse(cfg, cat); v; v = v->next) {<br>+                 if (!strcasecmp(v->name, "enabled")) {<br>+                          newenablecel = ast_true(v->value) ? 1 : 0;<br>+                        } else if (!strcasecmp(v->name, "host")) {<br>+                              ast_free(bs_host);<br>+                           bs_host = ast_strdup(v->value);<br>+                   } else if (!strcasecmp(v->name, "port")) {<br>+                              bs_port = atoi(v->value);<br>+                 } else if (!strcasecmp(v->name, "tube")) {<br>+                              ast_free(bs_tube);<br>+                           bs_tube = ast_strdup(v->value);<br>+                   } else if (!strcasecmp(v->name, "priority")) {<br>+                          priority = atoi(v->value);<br>+                        } else {<br>+                             ast_log(LOG_NOTICE, "Unknown option '%s' specified "<br>+                                               "for CEL beanstalk backend.\n", v->name);<br>+                       }<br>+            }<br>+    }<br>+<br>+ if (reload) {<br>+                ast_rwlock_unlock(&config_lock);<br>+ }<br>+<br>+ ast_config_destroy(cfg);<br>+<br>+  if (enablecel && !newenablecel) {<br>+            ast_cel_backend_unregister(CEL_BACKEND_NAME);<br>+        } else if (!enablecel && newenablecel) {<br>+             if (ast_cel_backend_register(CEL_BACKEND_NAME, cel_bs_put)) {<br>+                        ast_log(LOG_ERROR, "Unable to register Beanstalkd CEL handling\n");<br>+                }<br>+    }<br>+<br>+ enablecel = newenablecel;<br>+<br>+ return 0;<br>+}<br>+<br>+static int unload_module(void)<br>+{<br>+        ast_cel_backend_unregister(CEL_BACKEND_NAME);<br>+        ast_free(bs_host);<br>+   ast_free(bs_tube);<br>+   return 0;<br>+}<br>+<br>+static int load_module(void)<br>+{<br>+  if (load_config(0)) {<br>+                return AST_MODULE_LOAD_DECLINE;<br>+      }<br>+<br>+ return AST_MODULE_LOAD_SUCCESS;<br>+}<br>+<br>+static int reload(void)<br>+{<br>+ return load_config(1);<br>+}<br>+<br>+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Beanstalkd CEL Backend",<br>+        .support_level = AST_MODULE_SUPPORT_EXTENDED,<br>+        .load = load_module,<br>+ .unload = unload_module,<br>+     .reload = reload,<br>+    .load_pri = AST_MODPRI_CDR_DRIVER,<br>+);<br>diff --git a/configs/samples/cel_beanstalkd.conf.sample b/configs/samples/cel_beanstalkd.conf.sample<br>new file mode 100644<br>index 0000000..8cd0134<br>--- /dev/null<br>+++ b/configs/samples/cel_beanstalkd.conf.sample<br>@@ -0,0 +1,21 @@<br>+;<br>+; Beanstalkd Job Queue Server CEL Backend<br>+;<br>+[general]<br>+<br>+; Backend Activation<br>+;<br>+; Use the 'enabled' keyword to turn CEL logging<br>+; on or off.<br>+;<br>+; Accepted values: yes and no<br>+; Default value:   no<br>+;enabled = yes<br>+<br>+;host = 127.0.0.1    ; Specify the remote IP address of the Beanstalkd server<br>+;port = 11300        ; Specify the remote PORT of the the Beanstalkd server<br>+;tube = asterisk-cel ; Specify the default CDR job queue to use<br>+;priority = 99       ; Specify the default job priority for the queue. This parameter is useful when building<br>+                     ; platform with multiple Asterisk servers, that are used for different functions. For example,<br>+                     ; none billable CDR records can be inserted with a priority of 99, while billable ones be<br>+                     ; inserted with a priority of 1<br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/6841">change 6841</a>. To unsubscribe, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/6841"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: merged </div>
<div style="display:none"> Gerrit-Change-Id: Ic3a087faeeac045d69a2a018e60e29831ddb95ab </div>
<div style="display:none"> Gerrit-Change-Number: 6841 </div>
<div style="display:none"> Gerrit-PatchSet: 6 </div>
<div style="display:none"> Gerrit-Owner: Nir Simionovich (GreenfieldTech - Israel) <nirs@greenfieldtech.net> </div>
<div style="display:none"> Gerrit-Reviewer: Corey Farrell <git@cfware.com> </div>
<div style="display:none"> Gerrit-Reviewer: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins2 </div>
<div style="display:none"> Gerrit-Reviewer: Joshua Colp <jcolp@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Matthew Fredrickson <creslin@digium.com> </div>