fd655522a0a7724d799a1a48c846fde0c04151f8
[apps/agl-service-data-persistence.git] / ll-store-binding / src / ll-store-binding.c
1 #define _GNU_SOURCE
2 #include <stdio.h>
3 #include <string.h>
4 #include <json-c/json.h>
5 #include <lmdb.h>
6
7 #define AFB_BINDING_VERSION 2
8 #include <afb/afb-binding.h>
9
10 #define DB_FILE "/home/agl/projects/ll-store-binding/build/src/ll-store-binding.lmdb"
11
12 MDB_env* dbenv;
13
14 /// @brief Get a string from a json object.
15 /// @param[in] obj Json object from wich the string is queried.
16 /// @param[in] name Name of the string to get.
17 /// @return 
18 const char* get_json_string(struct json_object* obj, const char* name)
19 {
20         if (!obj || !name || !strlen(name)) return NULL;
21         
22         struct json_object* item = NULL;
23         if (!json_object_object_get_ex(obj, name, &item) || !item) return NULL;
24
25         return json_object_get_string(item);
26 }
27
28 char* make_key(const char* username, const char* appname, const char* tagname)
29 {
30         size_t sz_username = username ? strlen(username) : 0;
31         size_t sz_appname = appname ? strlen(appname) : 0;
32         size_t sz_tagname = tagname ? strlen(tagname) : 0;
33         size_t sz_total = sz_username + sz_appname + sz_tagname + 3;
34
35         char* result = (char*)malloc(sz_total);
36         memset(result, sz_total, 0);
37
38         strcpy(result, username);
39         result[sz_username] = '.';
40         
41         strcpy(result + sz_username + 1, appname);
42         result[sz_username + 1 + sz_appname] = '.';
43
44         strcpy(result + sz_username + 1 + sz_appname + 1, tagname);
45         
46         return result;
47 }
48
49 static void verb_get(struct afb_req req)
50 {
51         int r;
52         struct json_object* args = afb_req_json(req);
53
54         AFB_INFO("args:\n%s\n", json_object_to_json_string_ext(args, JSON_C_TO_STRING_PRETTY));
55
56         const char* username = get_json_string(args, "username");
57         const char* appname = get_json_string(args, "appname");
58         const char* tagname = get_json_string(args, "tagname");
59
60         if (!username || !appname || !tagname)
61         {
62                 AFB_ERROR("[store] username, appname and tagname must be provided!");
63                 afb_req_fail(req, "username, appname and tagname must be provided!", NULL);
64                 return;
65         }
66
67         char* keyname = make_key(username, appname, tagname);
68
69         MDB_txn* txn;
70         r = mdb_txn_begin(dbenv, NULL, 0, &txn);
71         if (r)
72         {
73                 free(keyname);
74                 AFB_ERROR("Failed to begin a transaction!");
75                 afb_req_fail(req, "Failed to begin a transaction!", NULL);
76                 return;
77         }
78
79         MDB_dbi dbi;
80         r = mdb_dbi_open(txn, NULL, 0, &dbi);
81         if (r)
82         {
83                 free(keyname);
84                 mdb_txn_abort(txn);
85                 AFB_ERROR("Failed to open the database!");
86                 afb_req_fail(req, "Failed to open the database!", NULL);
87                 return;
88         }
89
90         MDB_val k;
91         MDB_val v;
92         k.mv_size = strlen(keyname) + 1;
93         k.mv_data = keyname;
94
95         if(mdb_get(txn, dbi, &k, &v))
96         {
97                 free(keyname);
98                 mdb_txn_abort(txn);
99                 mdb_dbi_close(dbenv, dbi);
100                 AFB_ERROR("Failed to get the data!");
101                 afb_req_fail(req, "Failed to get the data!", NULL);
102                 return;
103         }
104
105         char* value = strndup(v.mv_data, v.mv_size + 1);
106         if(mdb_txn_commit(txn))
107         {
108                 free(keyname);
109                 free(value);
110                 mdb_dbi_close(dbenv, dbi);
111                 AFB_ERROR("Failed to commit the transaction!");
112                 return;
113         }
114                 
115         json_object* result = json_object_new_object();
116         json_object_object_add(result, "key", json_object_new_string(keyname));
117         json_object_object_add(result, "value", json_object_new_string(value));
118         afb_req_success(req, result, NULL);
119
120         free(value);
121         free(keyname);
122         return;
123 }
124
125 static void verb_set(struct afb_req req)
126 {
127         int r;
128         struct json_object* args = afb_req_json(req);
129
130         AFB_INFO("args:\n%s\n", json_object_to_json_string_ext(args, JSON_C_TO_STRING_PRETTY));
131
132         const char* username = get_json_string(args, "username");
133         const char* appname = get_json_string(args, "appname");
134         const char* tagname = get_json_string(args, "tagname");
135         const char* value = get_json_string(args, "value");
136
137         if (!username || !appname || !tagname)
138         {
139                 AFB_ERROR("[store] username, appname and tagname must be provided!");
140                 afb_req_fail(req, "username, appname and tagname must be provided!", NULL);
141                 return;
142         }
143
144         char* keyname = make_key(username, appname, tagname);
145
146         MDB_txn* txn;
147         r = mdb_txn_begin(dbenv, NULL, 0, &txn);
148         if (r)
149         {
150                 free(keyname);
151                 AFB_ERROR("Failed to begin a transaction!");
152                 afb_req_fail(req, "Failed to begin a transaction!", NULL);
153                 return;
154         }
155
156         MDB_dbi dbi;
157         r = mdb_dbi_open(txn, NULL, 0, &dbi);
158         if (r)
159         {
160                 free(keyname);
161                 mdb_txn_abort(txn);
162                 AFB_ERROR("Failed to open the database!");
163                 afb_req_fail(req, "Failed to open the database!", NULL);
164                 return;
165         }
166
167         MDB_val k;
168         MDB_val v;
169         k.mv_size = strlen(keyname) + 1;
170         k.mv_data = keyname;
171         v.mv_size = value ? strlen(value) + 1 : 0;
172         v.mv_data = value;
173
174         if(mdb_put(txn, dbi, &k, &v, 0))
175         {
176                 free(keyname);
177                 mdb_txn_abort(txn);
178                 mdb_dbi_close(dbenv, dbi);
179                 AFB_ERROR("Failed to get the data!");
180                 afb_req_fail(req, "Failed to get the data!", NULL);
181                 return;
182         }
183
184         if(mdb_txn_commit(txn))
185         {
186                 free(keyname);
187                 mdb_dbi_close(dbenv, dbi);
188                 AFB_ERROR("Failed to commit the transaction!");
189                 return;
190         }
191                 
192         json_object* result = json_object_new_object();
193         json_object_object_add(result, "key", json_object_new_string(keyname));
194         json_object_object_add(result, "value", json_object_new_string(value));
195         afb_req_success(req, result, NULL);
196
197         free(keyname);
198         return;
199 }
200
201 int ll_store_preinit()
202 {
203         int r = mdb_env_create(&dbenv);
204         if (r)
205         {
206                 AFB_INFO("Failed to create MDB environment!");
207                 dbenv = NULL;
208                 return r;
209         }
210
211         r = mdb_env_open(dbenv, "/home/agl/ll-store-binding.lmdb", MDB_NOSUBDIR, 0644);
212         if (r)
213         {
214                 mdb_env_close(dbenv);
215                 dbenv = NULL;
216                 AFB_INFO("Failed to open MDB environment!");
217                 return r;
218         }
219
220 /*
221         MDB_txn* txn;
222         r = mdb_txn_begin(dbenv, NULL, 0, &txn);
223         if (r)
224         {
225                 mdb_env_close(dbenv);
226                 dbenv = NULL;
227                 AFB_INFO("Failed to begin a transaction!");
228                 return r;
229         }
230
231         MDB_dbi dbi;
232         r = mdb_dbi_open(txn, NULL, 0, &dbi);
233         if (r)
234         {
235                 mdb_env_close(dbenv);
236                 AFB_INFO("Failed to open the database!");
237                 dbenv = NULL;
238         }
239 */
240         return 0;
241 }
242
243 static const afb_verb_v2 _ll_store_binding_verbs[]= {
244         {
245                 .verb = "get",
246                 .callback = verb_get,
247                 .auth = NULL,
248                 .info = NULL,
249                 .session = AFB_SESSION_NONE_V2
250         },
251         {
252                 .verb = "set",
253                 .callback = verb_set,
254                 .auth = NULL,
255                 .info = NULL,
256                 .session = AFB_SESSION_NONE_V2
257         },
258         { .verb=NULL}
259 };
260
261 const struct afb_binding_v2 afbBindingV2 = {
262                 .api = "ll-store",
263                 .specification = NULL,
264                 .verbs = _ll_store_binding_verbs,
265                 .preinit = ll_store_preinit,
266                 .init = NULL,
267                 .onevent = NULL,
268                 .noconcurrency = 0
269 };