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