avoid to use a specific provider field
[psensor.git] / src / rsensor.c
1 /*
2  * Copyright (C) 2010-2014 jeanfi@gmail.com
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301 USA
18  */
19 #include <locale.h>
20 #include <libintl.h>
21 #define _(str) gettext(str)
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include <curl/curl.h>
28
29 #include <psensor_json.h>
30 #include <rsensor.h>
31 #include <server/server.h>
32 #include <url.h>
33
34 struct ucontent {
35         char *data;
36         size_t len;
37 };
38
39 static CURL *curl;
40
41 static const char *get_url(struct psensor *s)
42 {
43         return (char *)s->provider_data;
44 }
45
46 static size_t cbk_curl(void *buffer, size_t size, size_t nmemb, void *userp)
47 {
48         size_t realsize;
49         struct ucontent *mem;
50
51         realsize = size * nmemb;
52         mem = (struct ucontent *)userp;
53
54         mem->data = realloc(mem->data, mem->len + realsize + 1);
55
56         memcpy(&(mem->data[mem->len]), buffer, realsize);
57         mem->len += realsize;
58         mem->data[mem->len] = 0;
59
60         return realsize;
61 }
62
63 static char *create_api_1_1_sensors_url(const char *base_url)
64 {
65         char *nurl, *ret;
66         int n;
67
68         nurl = url_normalize(base_url);
69         n = strlen(nurl) + strlen(URL_BASE_API_1_1_SENSORS) + 1;
70         ret = malloc(n);
71
72         strcpy(ret, nurl);
73         strcat(ret, URL_BASE_API_1_1_SENSORS);
74
75         free(nurl);
76
77         return ret;
78 }
79
80 void rsensor_init(void)
81 {
82         curl = curl_easy_init();
83 }
84
85 void rsensor_cleanup(void)
86 {
87         curl_easy_cleanup(curl);
88 }
89
90 static json_object *get_json_object(const char *url)
91 {
92         struct ucontent chunk;
93         json_object *obj;
94
95         obj = NULL;
96
97         if (!curl)
98                 return NULL;
99
100         chunk.data = malloc(1);
101         chunk.len = 0;
102
103         curl_easy_setopt(curl, CURLOPT_URL, url);
104         curl_easy_setopt(curl, CURLOPT_VERBOSE, 0);
105         curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cbk_curl);
106         curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
107
108         log_debug("HTTP request %s", url);
109         if (curl_easy_perform(curl) == CURLE_OK)
110                 obj = json_tokener_parse(chunk.data);
111         else
112                 log_printf(LOG_ERR, _("Fail to connect to: %s"), url);
113
114         free(chunk.data);
115
116         return obj;
117 }
118
119 struct psensor **get_remote_sensors(const char *server_url,
120                                     int values_max_length)
121 {
122         struct psensor **sensors, *s;
123         char *url;
124         json_object *obj;
125         int i, n;
126
127         sensors = NULL;
128
129         url = create_api_1_1_sensors_url(server_url);
130
131         obj = get_json_object(url);
132
133         if (obj && !is_error(obj)) {
134                 n = json_object_array_length(obj);
135                 sensors = malloc((n + 1) * sizeof(struct psensor *));
136
137                 for (i = 0; i < n; i++) {
138                         s = psensor_new_from_json
139                                 (json_object_array_get_idx(obj, i),
140                                  url,
141                                  values_max_length);
142                         sensors[i] = s;
143                 }
144
145                 sensors[n] = NULL;
146
147                 json_object_put(obj);
148         } else {
149                 log_printf(LOG_ERR, _("Invalid content: %s"), url);
150         }
151
152         free(url);
153
154         if (!sensors) {
155                 sensors = malloc(sizeof(struct psensor *));
156                 *sensors = NULL;
157         }
158
159         return sensors;
160 }
161
162 static void remote_psensor_update(struct psensor *s)
163 {
164         json_object *obj;
165
166         obj = get_json_object(get_url(s));
167
168         if (obj && !is_error(obj)) {
169                 json_object *om;
170
171                 json_object_object_get_ex(obj, "last_measure", &om);
172
173                 if (!is_error(obj)) {
174                         json_object *ov, *ot;
175                         struct timeval tv;
176
177                         json_object_object_get_ex(om, "value", &ov);
178                         json_object_object_get_ex(om, "time", &ot);
179
180                         tv.tv_sec = json_object_get_int(ot);
181                         tv.tv_usec = 0;
182
183                         psensor_set_current_measure
184                             (s, json_object_get_double(ov), tv);
185                 }
186
187                 json_object_put(obj);
188         } else {
189                 log_printf(LOG_ERR, _("Invalid JSON: %s"), get_url(s));
190         }
191
192 }
193
194 void remote_psensor_list_update(struct psensor **sensors)
195 {
196         struct psensor **cur;
197
198         cur = sensors;
199         while (*cur) {
200                 struct psensor *s = *cur;
201
202                 if (s->type & SENSOR_TYPE_REMOTE)
203                         remote_psensor_update(s);
204
205                 cur++;
206         }
207 }