added support of next_collection for bpph
[ppastats.git] / src / lp_ws.c
1 /*
2     Copyright (C) 2011 jeanfi@gmail.com
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU 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
20 #include <stdlib.h>
21 #include <string.h>
22
23 #include <curl/curl.h>
24 #include <json/json.h>
25
26 #include "cache.h"
27 #include "list.h"
28 #include "lp_ws.h"
29 #include "lp_json.h"
30 #include "ppastats.h"
31
32 #define QUERY_GET_PUBLISHED_BINARIES \
33         "?ws.op=getPublishedBinaries"
34 #define QUERY_GET_DOWNLOAD_COUNT "?ws.op=getDownloadCount"
35 #define QUERY_GET_DAILY_DOWNLOAD_TOTALS \
36         "?ws.op=getDailyDownloadTotals"
37
38 static CURL *curl;
39
40 struct ucontent {
41         char *data;
42         size_t len;
43 };
44
45 static size_t cbk_curl(void *buffer, size_t size, size_t nmemb, void *userp)
46 {
47         size_t realsize = size * nmemb;
48         struct ucontent *mem = (struct ucontent *)userp;
49
50         mem->data = realloc(mem->data, mem->len + realsize + 1);
51
52         memcpy(&(mem->data[mem->len]), buffer, realsize);
53         mem->len += realsize;
54         mem->data[mem->len] = 0;
55
56         return realsize;
57 }
58
59 static char *fetch_url(const char *url)
60 {
61         struct ucontent *content = malloc(sizeof(struct ucontent));
62         char *result = NULL;
63         long code;
64
65         if (debug)
66                 printf("DEBUG: fetch_url %s\n", url);
67
68         if (!curl) {
69                 curl_global_init(CURL_GLOBAL_ALL);
70                 curl = curl_easy_init();
71         }
72
73         if (!curl)
74                 exit(EXIT_FAILURE);
75
76         content->data = malloc(1);
77         content->data[0] = '\0';
78         content->len = 0;
79
80         curl_easy_setopt(curl, CURLOPT_URL, url);
81         curl_easy_setopt(curl, CURLOPT_VERBOSE, 0);
82         curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cbk_curl);
83         curl_easy_setopt(curl, CURLOPT_WRITEDATA, content);
84         curl_easy_setopt(curl, CURLOPT_USERAGENT, "ppastats/0.0");
85
86         if (curl_easy_perform(curl) == CURLE_OK) {
87
88                 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code);
89                 if (code == 200)
90                         result = content->data;
91         }
92
93         if (!result)
94                 free(content->data);
95
96         free(content);
97
98         return result;
99 }
100
101 static json_object *get_json_object(const char *url)
102 {
103         json_object *obj = NULL;
104         char *body;
105
106         body = fetch_url(url);
107
108         if (body) {
109                 obj = json_tokener_parse(body);
110
111                 free(body);
112
113                 return obj;
114         }
115
116         return NULL;
117 }
118
119 static void **list_add_list(void **list1, void **list2)
120 {
121         int n1, n2, n;
122         void **list;
123
124         n1 = list_length(list1);
125         n2 = list_length(list2);
126
127         n = n1 + n2 + 1;
128
129         list = malloc(sizeof(void *)*(n+1));
130
131         memcpy(list, list1, n1*sizeof(void *));
132         memcpy(list+n1, list2, n2*sizeof(void *));
133
134         list[n1+n2] = NULL;
135
136         free(list1);
137
138         return list;
139 }
140
141 #define json_object_to_bpph_list \
142 json_object_to_binary_package_publishing_history_list
143
144 struct binary_package_publishing_history * *
145 get_binary_package_publishing_history_list(const char *archive_url,
146                                            const char *package_status)
147 {
148         struct json_object *o_next;
149         char *url = malloc(strlen(archive_url)+
150                            strlen(QUERY_GET_PUBLISHED_BINARIES)+
151                            strlen("&status=")+
152                            9+
153                            1);
154         json_object *o;
155         void **result = NULL;
156
157         strcpy(url, archive_url);
158         strcat(url, QUERY_GET_PUBLISHED_BINARIES);
159
160         if (package_status) {
161                 strcat(url, "&status=");
162                 strcat(url, package_status);
163         }
164
165         while (url) {
166                 o = get_json_object(url);
167                 free(url);
168                 url = NULL;
169
170                 if (!o)
171                         break;
172
173                 result = list_add_list(result,
174                                        (void **)json_object_to_bpph_list(o));
175
176                 o_next = json_object_object_get(o, "next_collection_link");
177
178                 if (o_next)
179                         url = strdup(json_object_get_string(o_next));
180
181                 json_object_put(o);
182         }
183
184         return (struct binary_package_publishing_history **)result;
185 }
186
187 int get_download_count(const char *archive_url)
188 {
189         int n = strlen(archive_url) + strlen(QUERY_GET_DOWNLOAD_COUNT) + 1;
190         char *url = malloc(n);
191         int result;
192         json_object *obj;
193
194         strcpy(url, archive_url);
195         strcat(url, QUERY_GET_DOWNLOAD_COUNT);
196
197         obj = get_json_object(url);
198         free(url);
199
200         if (!obj)
201                 return -1;
202
203         result = json_object_get_int(obj);
204
205         json_object_put(obj);
206
207         return result;
208 }
209
210 const struct distro_arch_series *get_distro_arch_series(const char *url)
211 {
212         json_object *obj;
213         const struct distro_arch_series *distro;
214
215         distro = cache_get(url);
216         if (distro)
217                 return (struct distro_arch_series *)distro;
218
219         obj = get_json_object(url);
220
221         if (!obj)
222                 return NULL;
223
224         distro = json_object_to_distro_arch_series(obj);
225
226         json_object_put(obj);
227
228         cache_put(url, distro, (void (*)(void *))&distro_arch_series_free);
229
230         return distro;
231 }
232
233 const struct distro_series *get_distro_series(const char *url)
234 {
235         json_object *obj;
236         const struct distro_series *distro;
237
238         distro = cache_get(url);
239         if (distro)
240                 return (struct distro_series *)distro;
241
242         obj = get_json_object(url);
243
244         if (!obj)
245                 return NULL;
246
247         distro = json_object_to_distro_series(obj);
248
249         json_object_put(obj);
250
251         cache_put(url, distro, (void (*)(void *))&distro_series_free);
252
253         return distro;
254 }
255
256 struct daily_download_total **get_daily_download_totals(const char *binary_url)
257 {
258         char *url;
259         json_object *obj;
260         struct daily_download_total **result = NULL;
261
262         url = malloc(strlen(binary_url)+
263                      strlen(QUERY_GET_DAILY_DOWNLOAD_TOTALS)+1);
264
265         strcpy(url, binary_url);
266         strcat(url, QUERY_GET_DAILY_DOWNLOAD_TOTALS);
267
268         obj = get_json_object(url);
269
270         if (obj) {
271                 result = json_object_to_daily_download_totals(obj);
272                 json_object_put(obj);
273         }
274
275         free(url);
276
277         return result;
278 }
279
280 void lp_ws_cleanup()
281 {
282         if (debug)
283                 printf("DEBUG: cleanup CURL\n");
284
285         curl_easy_cleanup(curl);
286         curl_global_cleanup();
287 }