90777d1cd2dbb8dfb1900251a6fc1814548e3fec
[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 "log.h"
24
25 #define BASE_URL "http://son.tizen.online"
26 #define PATH_API_RACING "/api/racing"
27
28 typedef struct {
29     char *ap_mac;
30     cloud_request_car_list_data_cb cb;
31     void *user_data;
32 } car_api_get_request_context_t;
33
34 typedef struct {
35     car_info_t *car;
36     cloud_request_car_post_finish_cb cb;
37     void *user_data;
38 } car_api_post_request_context_t;
39
40 typedef struct {
41     long response_code;
42     char *response_msg;
43 } car_api_post_request_response_t;
44
45 typedef struct {
46     long response_code;
47     car_info_t **cars;
48     int size;
49 } car_api_get_request_response_t;
50
51 GQuark g_spawn_error_quark();
52 static void car_api_post_task_thread_cb(GTask *task, gpointer source_object, gpointer task_data, GCancellable *cancellable);
53 static void car_api_post_task_ready_cb(GObject *source_object, GAsyncResult *res, gpointer user_data);
54 static void car_api_post_task_context_free(car_api_post_request_context_t *context);
55 static void car_api_post_request_response_free(car_api_post_request_response_t *response);
56
57 static void car_api_get_task_context_free(car_api_get_request_context_t *context);
58 static void car_api_get_request_response_free(car_api_get_request_response_t *response);
59 static void car_api_get_task_thread_cb(GTask *task, gpointer source_object, gpointer task_data, GCancellable *cancellable);
60 static void car_api_get_task_ready_cb(GObject *source_object, GAsyncResult *res, gpointer user_data);
61
62 #define G_ERROR_DOMAIN g_spawn_error_quark()
63
64 GCancellable *cloud_request_api_racing_get(const char *ap_mac, cloud_request_car_list_data_cb cb, void *user_data)
65 {
66     GCancellable *cancellable = g_cancellable_new();
67
68     GTask *task = g_task_new(NULL, cancellable, car_api_get_task_ready_cb, NULL);
69     g_task_set_source_tag(task, cloud_request_api_racing_get);
70     g_task_set_return_on_cancel(task, FALSE);
71
72     car_api_get_request_context_t *context = g_new0(car_api_get_request_context_t, 1);
73     context->ap_mac = strndup(ap_mac, strlen(ap_mac));
74     context->cb = cb;
75     context->user_data = user_data;
76
77     g_task_set_task_data(task, context, (GDestroyNotify)car_api_get_task_context_free);
78     g_task_run_in_thread(task, car_api_get_task_thread_cb);
79
80     g_object_unref(task);
81
82     return cancellable;
83 }
84
85 GCancellable *cloud_request_api_racing_post(const car_info_t *car_info, cloud_request_car_post_finish_cb cb, void *user_data)
86 {
87     GCancellable *cancellable = g_cancellable_new();
88
89     GTask *task = g_task_new(NULL, cancellable, car_api_post_task_ready_cb, NULL);
90     g_task_set_source_tag(task, cloud_request_api_racing_post);
91     g_task_set_return_on_cancel(task, FALSE);
92
93     car_api_post_request_context_t *context = g_new0(car_api_post_request_context_t, 1);
94     context->car = car_info_copy(car_info);
95     context->cb = cb;
96     context->user_data = user_data;
97
98     g_task_set_task_data(task, context, (GDestroyNotify)car_api_post_task_context_free);
99     g_task_run_in_thread(task, car_api_post_task_thread_cb);
100
101     g_object_unref(task);
102
103     return cancellable;
104 }
105
106 GQuark g_spawn_error_quark()
107 {
108   return g_quark_from_static_string("cloud_request");
109 }
110
111 static void car_api_post_task_context_free(car_api_post_request_context_t *context)
112 {
113     ret_if(!context);
114
115     car_info_destroy(context->car);
116     g_free(context);
117 }
118
119 static void car_api_post_request_response_free(car_api_post_request_response_t *response)
120 {
121     ret_if(!response);
122
123     g_free(response->response_msg);
124     g_free(response);
125 }
126
127 static void car_api_post_task_thread_cb(GTask *task, gpointer source_object, gpointer task_data, GCancellable *cancellable)
128 {
129     car_api_post_request_context_t *context = (car_api_post_request_context_t *)task_data;
130
131     if (g_task_return_error_if_cancelled(task)) {
132         return;
133     }
134
135     car_api_post_request_response_t *response = g_new0(car_api_post_request_response_t, 1);
136
137     char *json = car_info_serializer_serialize(context->car);
138     int retval = http_request_post(BASE_URL""PATH_API_RACING, json, &(response->response_msg), &(response->response_code));
139     g_free(json);
140
141     if (retval != 0) {
142         GError *err = g_error_new(G_ERROR_DOMAIN, retval, "http_request_post failed!");
143         g_task_return_error(task, err);
144     }
145
146     g_task_return_pointer(task, response, (GDestroyNotify)car_api_post_request_response_free);
147 }
148
149 static void car_api_post_task_ready_cb(GObject *source_object, GAsyncResult *res, gpointer user_data)
150 {
151     GTask *task = G_TASK(res);
152     GError *error = NULL;
153
154     //If no error occurred g_task_propagate_pointer transfers ownership, so later response have to be freed.
155     car_api_post_request_response_t *response = g_task_propagate_pointer(task, &error);
156     if (error != NULL) {
157         _E("POST async task failed with msg: %s", error->message);
158         g_error_free(error);
159         return;
160     }
161     car_api_post_request_context_t *context = g_task_get_task_data(task);
162
163     request_result_e result = (response->response_code == 200 && (strcmp(response->response_msg, "Success") == 0)) ?
164         SUCCESS :
165         FAILURE;
166
167     if (context->cb) {
168         context->cb(result, context->user_data);
169     }
170
171     car_api_post_request_response_free(response);
172 }
173
174 static void car_api_get_task_context_free(car_api_get_request_context_t *context)
175 {
176     ret_if(!context);
177
178     g_free(context->ap_mac);
179     g_free(context);
180 }
181
182 static void car_api_get_request_response_free(car_api_get_request_response_t *response)
183 {
184     ret_if(!response);
185     ret_if(response->size <= 0);
186
187     for (int i = 0; i < response->size; i++)
188     {
189         car_info_destroy(response->cars[i]);
190     }
191     g_free(response->cars);
192     g_free(response);
193 }
194
195 static void car_api_get_task_thread_cb(GTask *task, gpointer source_object, gpointer task_data, GCancellable *cancellable)
196 {
197     car_api_get_request_context_t *context = (car_api_get_request_context_t *)task_data;
198
199     if (g_task_return_error_if_cancelled(task)) {
200         return;
201     }
202
203     car_api_get_request_response_t *response = g_new0(car_api_get_request_response_t, 1);
204     char *response_json = NULL;
205
206     GString *url = g_string_new(BASE_URL""PATH_API_RACING"?apMac=");
207     g_string_append(url, context->ap_mac);
208
209     int retval = http_request_get(url->str, &response_json, &(response->response_code));
210     g_string_free(url, TRUE);
211
212     if (retval != 0) {
213         GError *err = g_error_new(G_ERROR_DOMAIN, retval, "http_request_get failed!");
214         g_task_return_error(task, err);
215     }
216     else {
217         response->cars = car_info_serializer_deserialize_array(response_json, &(response->size));
218     }
219
220     g_free(response_json);
221     g_task_return_pointer(task, response, (GDestroyNotify)car_api_get_request_response_free);
222 }
223
224 static void car_api_get_task_ready_cb(GObject *source_object, GAsyncResult *res, gpointer user_data)
225 {
226     GTask *task = G_TASK(res);
227     GError *error = NULL;
228
229     //If no error occurred g_task_propagate_pointer transfers ownership, so later response have to be freed.
230     car_api_get_request_response_t *response = g_task_propagate_pointer(task, &error);
231     if (error != NULL) {
232         _E("GET async task failed with msg: %s", error->message);
233         g_error_free(error);
234         return;
235     }
236     car_api_get_request_context_t *context = g_task_get_task_data(task);
237
238     request_result_e result = (response->response_code == 200) ? SUCCESS : FAILURE;
239
240     if (context->cb) {
241         context->cb(result, response->cars, response->size, context->user_data);
242     }
243
244     car_api_get_request_response_free(response);
245 }