src/graph_instance.[ch]: Implement "inst_data_to_json".
[collection4.git] / src / graph_ident.c
index b008a56..3635990 100644 (file)
@@ -1,12 +1,44 @@
+/**
+ * collection4 - graph_ident.c
+ * Copyright (C) 2010  Florian octo Forster
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301  USA
+ *
+ * Authors:
+ *   Florian octo Forster <ff at octo.it>
+ **/
+
 #include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
 #include <string.h>
 #include <strings.h>
 #include <errno.h>
 #include <limits.h> /* PATH_MAX */
+#include <sys/types.h>
+#include <sys/stat.h>
 
 #include "graph_ident.h"
 #include "common.h"
+#include "data_provider.h"
 #include "filesystem.h"
+#include "utils_cgi.h"
+
+#include <fcgiapp.h>
+#include <fcgi_stdio.h>
 
 /*
  * Data types
@@ -63,8 +95,10 @@ static char *part_copy_with_selector (const char *selector, /* {{{ */
 static _Bool part_matches (const char *selector, /* {{{ */
     const char *part)
 {
+#if C4_DEBUG
   if ((selector == NULL) && (part == NULL))
     return (1);
+#endif
 
   if (selector == NULL) /* && (part != NULL) */
     return (0);
@@ -196,7 +230,7 @@ void ident_destroy (graph_ident_t *ident) /* {{{ */
 } /* }}} void ident_destroy */
 
 /* ident_get_* methods {{{ */
-const char *ident_get_host (graph_ident_t *ident) /* {{{ */
+const char *ident_get_host (const graph_ident_t *ident) /* {{{ */
 {
   if (ident == NULL)
     return (NULL);
@@ -204,7 +238,7 @@ const char *ident_get_host (graph_ident_t *ident) /* {{{ */
   return (ident->host);
 } /* }}} char *ident_get_host */
 
-const char *ident_get_plugin (graph_ident_t *ident) /* {{{ */
+const char *ident_get_plugin (const graph_ident_t *ident) /* {{{ */
 {
   if (ident == NULL)
     return (NULL);
@@ -212,7 +246,7 @@ const char *ident_get_plugin (graph_ident_t *ident) /* {{{ */
   return (ident->plugin);
 } /* }}} char *ident_get_plugin */
 
-const char *ident_get_plugin_instance (graph_ident_t *ident) /* {{{ */
+const char *ident_get_plugin_instance (const graph_ident_t *ident) /* {{{ */
 {
   if (ident == NULL)
     return (NULL);
@@ -220,7 +254,7 @@ const char *ident_get_plugin_instance (graph_ident_t *ident) /* {{{ */
   return (ident->plugin_instance);
 } /* }}} char *ident_get_plugin_instance */
 
-const char *ident_get_type (graph_ident_t *ident) /* {{{ */
+const char *ident_get_type (const graph_ident_t *ident) /* {{{ */
 {
   if (ident == NULL)
     return (NULL);
@@ -228,13 +262,33 @@ const char *ident_get_type (graph_ident_t *ident) /* {{{ */
   return (ident->type);
 } /* }}} char *ident_get_type */
 
-const char *ident_get_type_instance (graph_ident_t *ident) /* {{{ */
+const char *ident_get_type_instance (const graph_ident_t *ident) /* {{{ */
 {
   if (ident == NULL)
     return (NULL);
 
   return (ident->type_instance);
 } /* }}} char *ident_get_type_instance */
+
+const char *ident_get_field (const graph_ident_t *ident, /* {{{ */
+    graph_ident_field_t field)
+{
+  if ((ident == NULL) || (field >= _GIF_LAST))
+    return (NULL);
+
+  if (field == GIF_HOST)
+    return (ident->host);
+  else if (field == GIF_PLUGIN)
+    return (ident->plugin);
+  else if (field == GIF_PLUGIN_INSTANCE)
+    return (ident->plugin_instance);
+  else if (field == GIF_TYPE)
+    return (ident->type);
+  else if (field == GIF_TYPE_INSTANCE)
+    return (ident->type_instance);
+  else
+    return (NULL); /* never reached */
+} /* }}} const char *ident_get_field */
 /* }}} ident_get_* methods */
 
 /* ident_set_* methods {{{ */
@@ -350,12 +404,10 @@ int ident_compare (const graph_ident_t *i0, /* {{{ */
 _Bool ident_matches (const graph_ident_t *selector, /* {{{ */
     const graph_ident_t *ident)
 {
-  if ((selector == NULL) && (ident == NULL))
+#if C4_DEBUG
+  if ((selector == NULL) || (ident == NULL))
     return (0);
-  else if (selector == NULL)
-    return (-1);
-  else if (ident == NULL)
-    return (1);
+#endif
 
   if (!part_matches (selector->host, ident->host))
     return (0);
@@ -375,6 +427,27 @@ _Bool ident_matches (const graph_ident_t *selector, /* {{{ */
   return (1);
 } /* }}} _Bool ident_matches */
 
+_Bool ident_intersect (const graph_ident_t *s0, /* {{{ */
+    const graph_ident_t *s1)
+{
+#define INTERSECT_PART(p) do {                                               \
+  if (!IS_ANY (s0->p) && !IS_ALL (s0->p)                                     \
+      && !IS_ANY (s1->p) && !IS_ALL (s1->p)                                  \
+      && (strcmp (s0->p, s1->p) != 0))                                       \
+    return (0);                                                              \
+} while (0)
+
+  INTERSECT_PART (host);
+  INTERSECT_PART (plugin);
+  INTERSECT_PART (plugin_instance);
+  INTERSECT_PART (type);
+  INTERSECT_PART (type_instance);
+
+#undef INTERSECT_PART
+
+  return (1);
+} /* }}} _Bool ident_intersect */
+
 char *ident_to_string (const graph_ident_t *ident) /* {{{ */
 {
   char buffer[PATH_MAX];
@@ -430,26 +503,174 @@ char *ident_to_file (const graph_ident_t *ident) /* {{{ */
   return (strdup (buffer));
 } /* }}} char *ident_to_file */
 
-char *ident_to_json (const graph_ident_t *ident) /* {{{ */
+int ident_to_json (const graph_ident_t *ident, /* {{{ */
+    yajl_gen handler)
 {
-  char buffer[4096];
+  yajl_gen_status status;
 
-  buffer[0] = 0;
+  if ((ident == NULL) || (handler == NULL))
+    return (EINVAL);
 
-  strlcat (buffer, "{\"host\":\"", sizeof (buffer));
-  strlcat (buffer, ident->host, sizeof (buffer));
-  strlcat (buffer, "\",\"plugin\":\"", sizeof (buffer));
-  strlcat (buffer, ident->plugin, sizeof (buffer));
-  strlcat (buffer, "\",\"plugin_instance\":\"", sizeof (buffer));
-  strlcat (buffer, ident->plugin_instance, sizeof (buffer));
-  strlcat (buffer, "\",\"type\":\"", sizeof (buffer));
-  strlcat (buffer, ident->type, sizeof (buffer));
-  strlcat (buffer, "\",\"type_instance\":\"", sizeof (buffer));
-  strlcat (buffer, ident->type_instance, sizeof (buffer));
-  strlcat (buffer, "\"}", sizeof (buffer));
+#define ADD_STRING(str) do {                              \
+  status = yajl_gen_string (handler,                      \
+      (unsigned char *) (str),                            \
+      (unsigned int) strlen (str));                       \
+  if (status != yajl_gen_status_ok)                       \
+    return ((int) status);                                \
+} while (0)
 
-  return (strdup (buffer));
+  yajl_gen_map_open (handler);
+  ADD_STRING ("host");
+  ADD_STRING (ident->host);
+  ADD_STRING ("plugin");
+  ADD_STRING (ident->plugin);
+  ADD_STRING ("plugin_instance");
+  ADD_STRING (ident->plugin_instance);
+  ADD_STRING ("type");
+  ADD_STRING (ident->type);
+  ADD_STRING ("type_instance");
+  ADD_STRING (ident->type_instance);
+  yajl_gen_map_close (handler);
+
+#undef ADD_FIELD
+
+  return (0);
 } /* }}} char *ident_to_json */
 
+/* {{{ ident_data_to_json */
+struct ident_data_to_json__data_s
+{
+  dp_time_t begin;
+  dp_time_t end;
+  yajl_gen handler;
+};
+typedef struct ident_data_to_json__data_s ident_data_to_json__data_t;
+
+#define yajl_gen_string_cast(h,s,l) \
+  yajl_gen_string (h, (unsigned char *) s, (unsigned int) l)
+
+static int ident_data_to_json__get_ident_data (
+    __attribute__((unused)) graph_ident_t *ident, /* {{{ */
+    __attribute__((unused)) const char *ds_name,
+    const dp_data_point_t *dp, size_t dp_num,
+    void *user_data)
+{
+  ident_data_to_json__data_t *data = user_data;
+  size_t i;
+
+  yajl_gen_map_open (data->handler);
+
+  for (i = 0; i < dp_num; i++)
+  {
+    yajl_gen_map_open (data->handler);
+    yajl_gen_integer (data->handler, (long) dp[i].time.tv_sec);
+    yajl_gen_double (data->handler, dp[i].value);
+    yajl_gen_map_close (data->handler);
+  }
+
+  yajl_gen_map_close (data->handler);
+} /* }}} int ident_data_to_json__get_ident_data */
+
+/* Called for each DS name */
+static int ident_data_to_json__get_ds_name (const graph_ident_t *ident, /* {{{ */
+    const char *ds_name, void *user_data)
+{
+  ident_data_to_json__data_t *data = user_data;
+  int status;
+
+  yajl_gen_map_open (data->handler);
+
+  yajl_gen_string_cast (data->handler, "ds_name", strlen ("ds_name"));
+  yajl_gen_string_cast (data->handler, ds_name, strlen (ds_name));
+
+  yajl_gen_string_cast (data->handler, "data", strlen ("data"));
+  yajl_gen_array_open (data->handler);
+
+  status = data_provider_get_ident_data (ident, ds_name,
+      data->begin, data->end,
+      ident_data_to_json__get_ident_data,
+      data);
+
+  yajl_gen_array_close (data->handler);
+  yajl_gen_map_close (data->handler);
+
+  return (status);
+} /* }}} int ident_data_to_json__get_ds_name */
+
+int ident_data_to_json (const graph_ident_t *ident, /* {{{ */
+    dp_time_t begin, dp_time_t end,
+    yajl_gen handler)
+{
+  ident_data_to_json__data_t data;
+
+  data.begin = begin;
+  data.end = end;
+  data.handler = handler;
+
+  /* Iterate over all DS names */
+  return (data_provider_get_ident_ds_names (ident,
+        ident_data_to_json__get_ds_name, &data));
+} /* }}} int ident_data_to_json */
+/* }}} ident_data_to_json */
+
+int ident_describe (const graph_ident_t *ident, /* {{{ */
+    const graph_ident_t *selector,
+    char *buffer, size_t buffer_size)
+{
+  if ((ident == NULL) || (selector == NULL)
+      || (buffer == NULL) || (buffer_size < 2))
+    return (EINVAL);
+
+  buffer[0] = 0;
+
+#define CHECK_FIELD(field) do {                                              \
+  if (strcasecmp (selector->field, ident->field) != 0)                       \
+  {                                                                          \
+    if (buffer[0] != 0)                                                      \
+      strlcat (buffer, "/", buffer_size);                                    \
+    strlcat (buffer, ident->field, buffer_size);                             \
+  }                                                                          \
+} while (0)
+
+  CHECK_FIELD (host);
+  CHECK_FIELD (plugin);
+  CHECK_FIELD (plugin_instance);
+  CHECK_FIELD (type);
+  CHECK_FIELD (type_instance);
+
+#undef CHECK_FIELD
+
+  if (buffer[0] == 0)
+    strlcat (buffer, "default", buffer_size);
+
+  return (0);
+} /* }}} int ident_describe */
+
+time_t ident_get_mtime (const graph_ident_t *ident) /* {{{ */
+{
+  char *file;
+  struct stat statbuf;
+  int status;
+
+  if (ident == NULL)
+    return (0);
+
+  file = ident_to_file (ident);
+  if (file == NULL)
+    return (0);
+
+  memset (&statbuf, 0, sizeof (statbuf));
+  status = stat (file, &statbuf);
+  if (status != 0)
+  {
+    fprintf (stderr, "ident_get_mtime: stat'ing file \"%s\" failed: %s\n",
+        file, strerror (errno));
+    return (0);
+  }
+
+  free (file);
+  return (statbuf.st_mtime);
+} /* }}} time_t ident_get_mtime */
+
 /* vim: set sw=2 sts=2 et fdm=marker : */