4b51be80b31acd9f86710c86bb7529c45651cdea
[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 #define json_object_to_bpph_list \
120 json_object_to_binary_package_publishing_history_list
121
122 struct binary_package_publishing_history * *
123 get_binary_package_publishing_history_list(const char *archive_url,
124                                            const char *pkg_status)
125 {
126         struct json_object *o_next;
127         char *url;
128         json_object *o;
129         void **result = NULL;
130
131         url = malloc(strlen(archive_url)+
132                      strlen(QUERY_GET_PUBLISHED_BINARIES)+
133                      (pkg_status ? strlen("&status=")+strlen(pkg_status) : 0)+
134                      1);
135
136         strcpy(url, archive_url);
137         strcat(url, QUERY_GET_PUBLISHED_BINARIES);
138
139         if (pkg_status) {
140                 strcat(url, "&status=");
141                 strcat(url, pkg_status);
142         }
143
144         while (url) {
145                 o = get_json_object(url);
146                 free(url);
147                 url = NULL;
148
149                 if (!o)
150                         break;
151
152                 result = list_append_list(result,
153                                           (void **)json_object_to_bpph_list(o));
154
155                 o_next = json_object_object_get(o, "next_collection_link");
156
157                 if (o_next)
158                         url = strdup(json_object_get_string(o_next));
159
160                 json_object_put(o);
161         }
162
163         return (struct binary_package_publishing_history **)result;
164 }
165
166 int get_download_count(const char *archive_url)
167 {
168         int n = strlen(archive_url) + strlen(QUERY_GET_DOWNLOAD_COUNT) + 1;
169         char *url = malloc(n);
170         int result;
171         json_object *obj;
172
173         strcpy(url, archive_url);
174         strcat(url, QUERY_GET_DOWNLOAD_COUNT);
175
176         obj = get_json_object(url);
177         free(url);
178
179         if (!obj)
180                 return -1;
181
182         result = json_object_get_int(obj);
183
184         json_object_put(obj);
185
186         return result;
187 }
188
189 const struct distro_arch_series *get_distro_arch_series(const char *url)
190 {
191         json_object *obj;
192         const struct distro_arch_series *distro;
193
194         distro = cache_get(url);
195         if (distro)
196                 return (struct distro_arch_series *)distro;
197
198         obj = get_json_object(url);
199
200         if (!obj)
201                 return NULL;
202
203         distro = json_object_to_distro_arch_series(obj);
204
205         json_object_put(obj);
206
207         cache_put(url, distro, (void (*)(void *))&distro_arch_series_free);
208
209         return distro;
210 }
211
212 const struct distro_series *get_distro_series(const char *url)
213 {
214         json_object *obj;
215         const struct distro_series *distro;
216
217         distro = cache_get(url);
218         if (distro)
219                 return (struct distro_series *)distro;
220
221         obj = get_json_object(url);
222
223         if (!obj)
224                 return NULL;
225
226         distro = json_object_to_distro_series(obj);
227
228         json_object_put(obj);
229
230         cache_put(url, distro, (void (*)(void *))&distro_series_free);
231
232         return distro;
233 }
234
235 struct daily_download_total **get_daily_download_totals(const char *binary_url)
236 {
237         char *url;
238         json_object *obj;
239         struct daily_download_total **result = NULL;
240
241         url = malloc(strlen(binary_url)+
242                      strlen(QUERY_GET_DAILY_DOWNLOAD_TOTALS)+1);
243
244         strcpy(url, binary_url);
245         strcat(url, QUERY_GET_DAILY_DOWNLOAD_TOTALS);
246
247         obj = get_json_object(url);
248
249         if (obj) {
250                 result = json_object_to_daily_download_totals(obj);
251                 json_object_put(obj);
252         }
253
254         free(url);
255
256         return result;
257 }
258
259 void lp_ws_cleanup()
260 {
261         if (debug)
262                 printf("DEBUG: cleanup CURL\n");
263
264         curl_easy_cleanup(curl);
265         curl_global_cleanup();
266 }