Add experimental support for querying a sensor an arbitrary range of points
authorJeremy Tan <[email protected]>
Sat, 7 Sep 2013 13:52:29 +0000 (21:52 +0800)
committerJeremy Tan <[email protected]>
Sat, 7 Sep 2013 13:52:29 +0000 (21:52 +0800)
server/fastcgi.c
server/fastcgi.h
server/sensor.c
server/sensor.h

index 1bd520b..e41e375 100644 (file)
@@ -355,7 +355,7 @@ void * FCGI_RequestLoop (void *data)
                } else if (!strcmp("control", module)) {
                        module_handler = Control_Handler;
                } else if (!strcmp("sensors", module)) {
-                       module_handler = Sensor_Handler;
+                       module_handler = Sensor_Handler2;
                }
 
                context.current_module = module;
index f52a20a..9a37a6f 100644 (file)
@@ -16,7 +16,8 @@
 typedef enum StatusCodes {
        STATUS_OK = 1,
        STATUS_ERROR = -1,
-       STATUS_UNAUTHORIZED = -2
+       STATUS_UNAUTHORIZED = -2,
+       STATUS_OUTOFRANGE = -3
 } StatusCodes;
 
 typedef struct FCGIContext FCGIContext;
index c0c3ab1..3d5aec7 100644 (file)
@@ -135,6 +135,7 @@ void * Sensor_Main(void * arg)
                                Fatal("Error collecting data");
                        }
                        s->write_index += 1;
+                       //TODO: s->points_read not used?
                }
 
                //Log(LOGDEBUG, "Filled buffer");
@@ -149,6 +150,7 @@ void * Sensor_Main(void * arg)
                        {
                                Fatal("Wrote %d data points and expected to write %d to \"%s\" - %s", amount_written, SENSOR_DATABUFSIZ, strerror(errno));
                        }
+                       s->points_stored += amount_written;
                        //Log(LOGDEBUG, "Wrote %d data points for sensor %d", amount_written, s->id);
                pthread_mutex_unlock(&(s->mutex));
                // End of critical section
@@ -203,6 +205,99 @@ Sensor * Sensor_Identify(const char * id_str)
        return g_sensors+id;
 }
 
+/*
+ * Behaviour: 
+ * Dump true:
+ * - from < 0: From beginning of file, else from that point onwards (0-indexed)
+ * - count < 0: All points available, else *at most* that many points
+ * Dump false:
+ * - from < 0: From the end of file (last available points), else from that point onwards (0-indexed)
+ * - count < 0: Default buffer size (SENSOR_QUERYBUFSIZ), else *at most* that many points
+ */
+void Sensor_Handler2(FCGIContext *context, char *params)
+{
+       const char *key, *value;
+       int id = -1, from = -1, count = -1;
+       bool dump = false;
+
+       //Lazy checking
+       while ((params = FCGI_KeyPair(params, &key, &value))) {
+               if (!strcmp(key, "id") && *value) {
+                       char *end;
+                       id = strtol(value, &end, 10);
+                       if (*end != '\0')
+                               id = -1;
+               } else if (!strcmp(key, "dump")) {
+                       dump = !dump;
+               } else if (!strcmp(key, "from") && *value) {
+                       from = strtol(value, NULL, 10);
+               } else if (!strcmp(key, "count") && *value) {
+                       count = strtol(value, NULL, 10);
+               }
+       }
+
+       if (id < 0 || id >= NUMSENSORS) {
+               FCGI_RejectJSON(context, "Invalid sensor id specified.");
+               return;
+       }
+       
+       Sensor *sensor = &g_sensors[id];
+       DataPoint buffer[SENSOR_QUERYBUFSIZ];
+       int amount_read = 0, total = 0;
+       
+       //Critical section
+       pthread_mutex_lock(&(sensor->mutex));
+       if (from >= sensor->points_stored) {
+               FCGI_RejectJSONEx(context, STATUS_OUTOFRANGE, "Invalid range specified.");
+       } else if (dump) {
+               from =  (from < 0) ? 0 : from;
+               count = (count < 0) ? sensor->points_stored : count;
+
+               FCGI_PrintRaw("Content-type: text/plain\r\n"
+                       "Content-disposition: attachment;filename=%d.csv\r\n\r\n", id);
+
+               fseek(sensor->file, sizeof(DataPoint) * from, SEEK_SET);
+               //Force download with content-disposition
+               do {
+                       amount_read = fread(buffer, sizeof(DataPoint), SENSOR_QUERYBUFSIZ, sensor->file);
+                       for (int i = 0; i < amount_read && total < count; i++, total++) {
+                               FCGI_PrintRaw("%f\t%f\n", buffer[i].time_stamp, buffer[i].value);
+                       }
+               } while (amount_read > 0 && total < count);
+       } else {
+               count = (count < 0) ? SENSOR_QUERYBUFSIZ : count;
+               if (from < 0) {
+                       from = sensor->points_stored - count;
+                       if (from < 0)
+                               from = 0;
+               }
+               fseek(sensor->file, sizeof(DataPoint) * from, SEEK_SET);
+
+               FCGI_BeginJSON(context, STATUS_OK);     
+               FCGI_JSONLong("id", id); 
+               FCGI_JSONKey("data");
+               FCGI_JSONValue("[");
+               while (total < count) {
+                       amount_read = fread(buffer, sizeof(DataPoint), SENSOR_QUERYBUFSIZ, sensor->file);
+                       if (amount_read > 0) {
+                               FCGI_JSONValue("[%f, %f]", buffer[0].time_stamp, buffer[0].value);
+                               total++;
+                               for (int i = 1; i < amount_read && total < count; i++, total++)
+                                       FCGI_JSONValue(", [%f, %f]", buffer[i].time_stamp, buffer[i].value);
+                       } else {
+                               break;
+                       }
+               }
+               FCGI_JSONValue("]");
+
+               FCGI_JSONLong("total_points", sensor->points_stored);
+               FCGI_JSONLong("next_point", from + total);
+               FCGI_EndJSON(); 
+       }
+       pthread_mutex_unlock(&(sensor->mutex));
+       //End critical section
+}
+
 /**
  * Handle a request to the sensor module
  * @param context - The context to work in
index 8ae5660..9bdefda 100644 (file)
@@ -46,6 +46,8 @@ typedef struct
        long points_read;
        /** Binary file to write data into when buffer is full **/
        FILE * file;
+       /** Number of data points stored in file **/
+       long points_stored;
        /** Thread running the sensor **/
        pthread_t thread;
        /** Mutex to protect access to stuff **/
@@ -65,5 +67,6 @@ extern int Sensor_Query(Sensor * s, DataPoint * buffer, int bufsiz); // fill buf
 
 extern void Sensor_Handler(FCGIContext *context, char * params);
 
+extern void Sensor_Handler2(FCGIContext *context, char *params);
 #endif //_SENSOR_H
 

UCC git Repository :: git.ucc.asn.au