4 ** Copyright (c) <2009> <sebastien.pahl@dotcloud.com>
6 ** Permission is hereby granted, free of charge, to any person
7 ** obtaining a copy of this software and associated documentation
8 ** files (the "Software"), to deal in the Software without
9 ** restriction, including without limitation the rights to use,
10 ** copy, modify, merge, publish, distribute, sublicense, and/or sell
11 ** copies of the Software, and to permit persons to whom the
12 ** Software is furnished to do so, subject to the following
15 ** The above copyright notice and this permission notice shall be
16 ** included in all copies or substantial portions of the Software.
18 ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 ** OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 ** HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 ** WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 ** FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 ** OTHER DEALINGS IN THE SOFTWARE.
37 #include <utils_format_json.h>
40 #include <amqp_framing.h>
42 #define PLUGIN_NAME "amqp"
45 static char *host = NULL;
46 static char *vhost = NULL;
47 static char *user = NULL;
48 static char *password = NULL;
49 static char *exchange = NULL;
50 static char *routingkey = NULL;
52 static const char *config_keys[] =
63 static int config_keys_num = STATIC_ARRAY_SIZE(config_keys);
65 static int config_set(char **var, const char *value)
68 if ((*var = strdup(value)) == NULL)
73 static int config(const char *key, const char *value)
75 if (strcasecmp(key, "host") == 0)
76 return (config_set(&host, value));
77 else if(strcasecmp(key, "port") == 0)
81 tmp = service_name_to_port_number (value);
84 ERROR ("AMQP plugin: Cannot parse `%s' as a "
85 "service name (port number).", value);
92 else if (strcasecmp(key, "vhost") == 0)
93 return (config_set(&vhost, value));
94 else if (strcasecmp(key, "user") == 0)
95 return (config_set(&user, value));
96 else if (strcasecmp(key, "password") == 0)
97 return (config_set(&password, value));
98 else if (strcasecmp(key, "exchange") == 0)
99 return (config_set(&exchange, value));
100 else if (strcasecmp(key, "routingkey") == 0)
101 return (config_set(&routingkey, value));
105 static int amqp_write(const data_set_t *ds, const value_list_t *vl, user_data_t *user_data)
112 amqp_rpc_reply_t reply;
113 amqp_connection_state_t conn;
114 amqp_basic_properties_t props;
116 /* TODO: Don't create a new connection for each value that is to be dispatched. */
117 conn = amqp_new_connection();
118 if ((sockfd = amqp_open_socket(host, port)) < 0)
120 ERROR ("amqp plugin: amqp_open_socket failed.");
121 amqp_destroy_connection(conn);
124 amqp_set_sockfd(conn, sockfd);
125 reply = amqp_login(conn, vhost,
126 /* channel max = */ 0,
127 /* frame max = */ 131072,
129 /* authentication: */ AMQP_SASL_METHOD_PLAIN, user, password);
130 if (reply.reply_type != AMQP_RESPONSE_NORMAL)
132 ERROR ("amqp plugin: amqp_login (vhost = %s, user = %s) failed.",
134 amqp_destroy_connection(conn);
138 amqp_channel_open(conn, 1);
139 if (reply.reply_type != AMQP_RESPONSE_NORMAL)
141 ERROR ("amqp plugin: amqp_channel_open failed.");
142 amqp_connection_close(conn, AMQP_REPLY_SUCCESS);
143 amqp_destroy_connection(conn);
148 memset(buffer, 0, sizeof(buffer));
149 bfree = sizeof(buffer);
151 format_json_initialize(buffer, &bfill, &bfree);
152 /* TODO: Possibly add a config option "StoreRates" and pass the value along here. */
153 format_json_value_list(buffer, &bfill, &bfree, ds, vl,
155 format_json_finalize(buffer, &bfill, &bfree);
156 props._flags = AMQP_BASIC_CONTENT_TYPE_FLAG | AMQP_BASIC_DELIVERY_MODE_FLAG;
157 props.content_type = amqp_cstring_bytes("application/json");
158 props.delivery_mode = 2; /* persistent delivery mode */
159 error = amqp_basic_publish(conn,
161 amqp_cstring_bytes(exchange),
162 amqp_cstring_bytes(routingkey),
166 amqp_cstring_bytes(buffer));
169 ERROR ("amqp plugin: amqp_basic_publish failed with status %i.",
173 reply = amqp_channel_close(conn, 1, AMQP_REPLY_SUCCESS);
174 if (reply.reply_type != AMQP_RESPONSE_NORMAL)
176 reply = amqp_connection_close(conn, AMQP_REPLY_SUCCESS);
177 if (reply.reply_type != AMQP_RESPONSE_NORMAL)
179 amqp_destroy_connection(conn);
180 if (close(sockfd) < 0)
185 static int shutdown(void)
196 void module_register(void)
198 plugin_register_config(PLUGIN_NAME, config, config_keys, config_keys_num);
199 plugin_register_write(PLUGIN_NAME, amqp_write, NULL);
200 plugin_register_shutdown(PLUGIN_NAME, shutdown);
203 /* vim: set sw=4 sts=4 et : */