Fixed http response codes in post
[apps/native/gear-racing-car.git] / src / cloud / cloud_request.c
1 /*
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Flora License, Version 1.1 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://floralicense.org/license/
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "cloud/cloud_request.h"
18 #include "cloud/car_info_serializer.h"
19 #include "cloud/http_request.h"
20 #include <glib.h>
21 #include <gio/gio.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include "log.h"
25
26 #define PATH_API_RACING "/api/racing"
27 #define CONFIG_CAR_API_KEY "car"
28
29 typedef struct {
30     char *ap_mac;
31     cloud_request_car_list_data_cb cb;
32     void *user_data;
33 } car_api_get_request_context_t;
34
35 typedef struct {
36     car_info_t *car;
37     cloud_request_car_post_finish_cb cb;
38     void *user_data;
39 } car_api_post_request_context_t;
40
41 typedef struct {
42     long response_code;
43     char *response_msg;
44 } car_api_post_request_response_t;
45
46 typedef struct {
47     long response_code;
48     car_info_t **cars;
49     int size;
50 } car_api_get_request_response_t;
51
52 GQuark g_spawn_error_quark();
53 static void car_api_post_task_thread_cb(GTask *task, gpointer source_object, gpointer task_data, GCancellable *cancellable);
54 static void car_api_post_task_ready_cb(GObject *source_object, GAsyncResult *res, gpointer user_data);
55 static void car_api_post_task_context_free(car_api_post_request_context_t *context);
56 static void car_api_post_request_response_free(car_api_post_request_response_t *response);
57
58 static void car_api_get_task_context_free(car_api_get_request_context_t *context);
59 static void car_api_get_request_response_free(car_api_get_request_response_t *response);
60 static void car_api_get_task_thread_cb(GTask *task, gpointer source_object, gpointer task_data, GCancellable *cancellable);
61 static void car_api_get_task_ready_cb(GObject *source_object, GAsyncResult *res, gpointer user_data);
62
63 #define G_ERROR_DOMAIN g_spawn_error_quark()
64
65 GCancellable *cloud_request_api_racing_get(const char *ap_mac, cloud_request_car_list_data_cb cb, void *user_data)
66 {
67     GCancellable *cancellable = g_cancellable_new();
68
69     GTask *task = g_task_new(NULL, cancellable, car_api_get_task_ready_cb, NULL);
70     g_task_set_source_tag(task, cloud_request_api_racing_get);
71     g_task_set_return_on_cancel(task, FALSE);
72
73     car_api_get_request_context_t *context = g_new0(car_api_get_request_context_t, 1);
74     context->ap_mac = strndup(ap_mac, strlen(ap_mac));
75     context->cb = cb;
76     context->user_data = user_data;
77
78     g_task_set_task_data(task, context, (GDestroyNotify)car_api_get_task_context_free);
79     g_task_run_in_thread(task, car_api_get_task_thread_cb);
80
81     g_object_unref(task);
82
83     return cancellable;
84 }
85
86 GCancellable *cloud_request_api_racing_post(const car_info_t *car_info, cloud_request_car_post_finish_cb cb, void *user_data)
87 {
88     GCancellable *cancellable = g_cancellable_new();
89
90     GTask *task = g_task_new(NULL, cancellable, car_api_post_task_ready_cb, NULL);
91     g_task_set_source_tag(task, cloud_request_api_racing_post);
92     g_task_set_return_on_cancel(task, FALSE);
93
94     car_api_post_request_context_t *context = g_new0(car_api_post_request_context_t, 1);
95     context->car = car_info_copy(car_info);
96     context->cb = cb;
97     context->user_data = user_data;
98
99     g_task_set_task_data(task, context, (GDestroyNotify)car_api_post_task_context_free);
100     g_task_run_in_thread(task, car_api_post_task_thread_cb);
101
102     g_object_unref(task);
103
104     return cancellable;
105 }
106
107 GQuark g_spawn_error_quark()
108 {
109   return g_quark_from_static_string("cloud_request");
110 }
111
112 static void car_api_post_task_context_free(car_api_post_request_context_t *context)
113 {
114     ret_if(!context);
115
116     car_info_destroy(context->car);
117     g_free(context);
118 }
119
120 static void car_api_post_request_response_free(car_api_post_request_response_t *response)
121 {
122     ret_if(!response);
123
124     g_free(response->response_msg);
125     g_free(response);
126 }
127
128 static void car_api_post_task_thread_cb(GTask *task, gpointer source_object, gpointer task_data, GCancellable *cancellable)
129 {
130     car_api_post_request_context_t *context = (car_api_post_request_context_t *)task_data;
131
132     if (g_task_return_error_if_cancelled(task)) {
133         return;
134     }
135
136     car_api_post_request_response_t *response = g_new0(car_api_post_request_response_t, 1);
137
138     char *json = car_info_serializer_serialize(context->car);
139
140     char *url = http_request_get_url(PATH_API_RACING, CONFIG_CAR_API_KEY);
141
142     int retval = http_request_post(url, json, &(response->response_msg), &(response->response_code));
143     g_free(json);
144
145     _D("URL FROM CONFIG (RACING POST): %s", url);
146     free(url);
147
148     if (retval != 0) {
149         GError *err = g_error_new(G_ERROR_DOMAIN, retval, "http_request_post failed!");
150         g_task_return_error(task, err);
151     }
152
153     g_task_return_pointer(task, response, (GDestroyNotify)car_api_post_request_response_free);
154 }
155
156 static void car_api_post_task_ready_cb(GObject *source_object, GAsyncResult *res, gpointer user_data)
157 {
158     GTask *task = G_TASK(res);
159     GError *error = NULL;
160
161     //If no error occurred g_task_propagate_pointer transfers ownership, so later response have to be freed.
162     car_api_post_request_response_t *response = g_task_propagate_pointer(task, &error);
163     if (error != NULL) {
164         _E("POST async task failed with msg: %s", error->message);
165         g_error_free(error);
166         return;
167     }
168     car_api_post_request_context_t *context = g_task_get_task_data(task);
169
170     request_result_e result = (response->response_code == 200 || response->response_code == 201) ?
171         SUCCESS :
172         FAILURE;
173
174     if (context->cb) {
175         context->cb(result, context->user_data);
176     }
177
178     car_api_post_request_response_free(response);
179 }
180
181 static void car_api_get_task_context_free(car_api_get_request_context_t *context)
182 {
183     ret_if(!context);
184
185     g_free(context->ap_mac);
186     g_free(context);
187 }
188
189 static void car_api_get_request_response_free(car_api_get_request_response_t *response)
190 {
191     ret_if(!response);
192     ret_if(response->size <= 0);
193
194     for (int i = 0; i < response->size; i++)
195     {
196         car_info_destroy(response->cars[i]);
197     }
198     g_free(response->cars);
199     g_free(response);
200 }
201
202 static void car_api_get_task_thread_cb(GTask *task, gpointer source_object, gpointer task_data, GCancellable *cancellable)
203 {
204     car_api_get_request_context_t *context = (car_api_get_request_context_t *)task_data;
205
206     if (g_task_return_error_if_cancelled(task)) {
207         return;
208     }
209
210     car_api_get_request_response_t *response = g_new0(car_api_get_request_response_t, 1);
211     char *response_json = NULL;
212
213     char *url_with_api = http_request_get_url(PATH_API_RACING, CONFIG_CAR_API_KEY);
214
215     GString *url = g_string_new(url_with_api);
216     g_string_append(url, "?apMac=");
217     g_string_append(url, context->ap_mac);
218
219     free(url_with_api);
220     _D("URL FROM CONFIG (RACING GET): %s", url);
221
222     int retval = http_request_get(url->str, &response_json, &(response->response_code));
223     g_string_free(url, TRUE);
224
225     if (retval != 0) {
226         GError *err = g_error_new(G_ERROR_DOMAIN, retval, "http_request_get failed!");
227         g_task_return_error(task, err);
228     }
229     else {
230         response->cars = car_info_serializer_deserialize_array(response_json, &(response->size));
231     }
232
233     g_free(response_json);
234     g_task_return_pointer(task, response, (GDestroyNotify)car_api_get_request_response_free);
235 }
236
237 static void car_api_get_task_ready_cb(GObject *source_object, GAsyncResult *res, gpointer user_data)
238 {
239     GTask *task = G_TASK(res);
240     GError *error = NULL;
241
242     //If no error occurred g_task_propagate_pointer transfers ownership, so later response have to be freed.
243     car_api_get_request_response_t *response = g_task_propagate_pointer(task, &error);
244     if (error != NULL) {
245         _E("GET async task failed with msg: %s", error->message);
246         g_error_free(error);
247         return;
248     }
249     car_api_get_request_context_t *context = g_task_get_task_data(task);
250
251     request_result_e result = (response->response_code == 200) ? SUCCESS : FAILURE;
252
253     if (context->cb) {
254         context->cb(result, response->cars, response->size, context->user_data);
255     }
256
257     car_api_get_request_response_free(response);
258 }