Imported Upstream version 1.2.0
[psensor-pkg-debian.git] / src / rsensor.c
1 /*
2  * Copyright (C) 2010-2016 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 *PROVIDER_NAME = "rsensor";
42
43 static const char *get_url(struct psensor *s)
44 {
45         return (char *)s->provider_data;
46 }
47
48 static size_t cbk_curl(void *buffer, size_t size, size_t nmemb, void *userp)
49 {
50         size_t realsize;
51         struct ucontent *mem;
52
53         realsize = size * nmemb;
54         mem = (struct ucontent *)userp;
55
56         mem->data = realloc(mem->data, mem->len + realsize + 1);
57
58         memcpy(&(mem->data[mem->len]), buffer, realsize);
59         mem->len += realsize;
60         mem->data[mem->len] = 0;
61
62         return realsize;
63 }
64
65 static char *create_api_1_1_sensors_url(const char *base_url)
66 {
67         char *nurl, *ret;
68         int n;
69
70         nurl = url_normalize(base_url);
71         n = strlen(nurl) + strlen(URL_BASE_API_1_1_SENSORS) + 1;
72         ret = malloc(n);
73
74         strcpy(ret, nurl);
75         strcat(ret, URL_BASE_API_1_1_SENSORS);
76
77         free(nurl);
78
79         return ret;
80 }
81
82 void rsensor_init(void)
83 {
84         curl = curl_easy_init();
85 }
86
87 void rsensor_cleanup(void)
88 {
89         curl_easy_cleanup(curl);
90 }
91
92 static json_object *get_json_object(const char *url)
93 {
94         struct ucontent chunk;
95         json_object *obj;
96
97         obj = NULL;
98
99         if (!curl)
100                 return NULL;
101
102         chunk.data = malloc(1);
103         chunk.len = 0;
104
105         curl_easy_setopt(curl, CURLOPT_URL, url);
106         curl_easy_setopt(curl, CURLOPT_VERBOSE, 0);
107         curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cbk_curl);
108         curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
109
110         log_fct("%s: HTTP request %s", PROVIDER_NAME, url);
111
112         if (curl_easy_perform(curl) == CURLE_OK)
113                 obj = json_tokener_parse(chunk.data);
114         else
115                 log_err(_("%s: Fail to connect to: %s"), PROVIDER_NAME, url);
116
117         free(chunk.data);
118
119         return obj;
120 }
121
122 struct psensor **get_remote_sensors(const char *server_url,
123                                     int values_max_length)
124 {
125         struct psensor **sensors, *s;
126         char *url;
127         json_object *obj;
128         int i, n;
129
130         sensors = NULL;
131
132         url = create_api_1_1_sensors_url(server_url);
133
134         obj = get_json_object(url);
135
136         if (obj && !is_error(obj)) {
137                 n = json_object_array_length(obj);
138                 sensors = malloc((n + 1) * sizeof(struct psensor *));
139
140                 for (i = 0; i < n; i++) {
141                         s = psensor_new_from_json
142                                 (json_object_array_get_idx(obj, i),
143                                  url,
144                                  values_max_length);
145                         sensors[i] = s;
146                 }
147
148                 sensors[n] = NULL;
149
150                 json_object_put(obj);
151         } else {
152                 log_err(_("%s: Invalid content: %s"), PROVIDER_NAME, url);
153         }
154
155         free(url);
156
157         if (!sensors) {
158                 sensors = malloc(sizeof(struct psensor *));
159                 *sensors = NULL;
160         }
161
162         return sensors;
163 }
164
165 static void remote_psensor_update(struct psensor *s)
166 {
167         json_object *obj;
168
169         obj = get_json_object(get_url(s));
170
171         if (obj && !is_error(obj)) {
172                 json_object *om;
173
174                 json_object_object_get_ex(obj, "last_measure", &om);
175
176                 if (!is_error(obj)) {
177                         json_object *ov, *ot;
178                         struct timeval tv;
179
180                         json_object_object_get_ex(om, "value", &ov);
181                         json_object_object_get_ex(om, "time", &ot);
182
183                         tv.tv_sec = json_object_get_int(ot);
184                         tv.tv_usec = 0;
185
186                         psensor_set_current_measure
187                             (s, json_object_get_double(ov), tv);
188                 }
189
190                 json_object_put(obj);
191         } else {
192                 log_err(_("%s: Invalid JSON: %s"), PROVIDER_NAME, get_url(s));
193         }
194
195 }
196
197 void remote_psensor_list_update(struct psensor **sensors)
198 {
199         struct psensor **cur;
200
201         cur = sensors;
202         while (*cur) {
203                 struct psensor *s = *cur;
204
205                 if (s->type & SENSOR_TYPE_REMOTE)
206                         remote_psensor_update(s);
207
208                 cur++;
209         }
210 }