From e7cf408f6d143724ca84119d35f5091f9c3be702 Mon Sep 17 00:00:00 2001 From: Loïc Collignon Date: Tue, 19 Dec 2017 17:14:33 +0100 Subject: renamed api to match better the repo name and the feature provided. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I688950d9da5b3db903815a2869767d00df66b6cf Signed-off-by: Loïc Collignon --- ll-database-binding/conf.d/cmake/config.cmake | 2 +- ll-database-binding/conf.d/wgt/config.xml.in | 4 +- ll-database-binding/src/CMakeLists.txt | 13 +- ll-database-binding/src/ll-database-binding.c | 469 -------------------------- ll-database-binding/src/persistence-binding.c | 469 ++++++++++++++++++++++++++ 5 files changed, 481 insertions(+), 476 deletions(-) delete mode 100644 ll-database-binding/src/ll-database-binding.c create mode 100644 ll-database-binding/src/persistence-binding.c diff --git a/ll-database-binding/conf.d/cmake/config.cmake b/ll-database-binding/conf.d/cmake/config.cmake index 37f7e76..b1bcde1 100644 --- a/ll-database-binding/conf.d/cmake/config.cmake +++ b/ll-database-binding/conf.d/cmake/config.cmake @@ -18,7 +18,7 @@ # Project Info # ------------------ -set(PROJECT_NAME ll-database) +set(PROJECT_NAME persistence-binding) set(PROJECT_VERSION "0.1") set(PROJECT_PRETTY_NAME "Low Level Database Binding") set(PROJECT_DESCRIPTION "") diff --git a/ll-database-binding/conf.d/wgt/config.xml.in b/ll-database-binding/conf.d/wgt/config.xml.in index 9209494..bbd3212 100644 --- a/ll-database-binding/conf.d/wgt/config.xml.in +++ b/ll-database-binding/conf.d/wgt/config.xml.in @@ -11,9 +11,9 @@ - + - + diff --git a/ll-database-binding/src/CMakeLists.txt b/ll-database-binding/src/CMakeLists.txt index cea11a3..95a481a 100644 --- a/ll-database-binding/src/CMakeLists.txt +++ b/ll-database-binding/src/CMakeLists.txt @@ -1,4 +1,4 @@ -PROJECT_TARGET_ADD(ll-database-binding) +PROJECT_TARGET_ADD(persistence-binding) find_package(GDBM) if(DB_FOUND) @@ -8,11 +8,16 @@ else(DB_FOUND) endif(DB_FOUND) include_directories(${DB_INCLUDE_DIR}) -add_library(ll-database-binding MODULE ll-database-binding.c) -target_link_libraries(ll-database-binding ${DB_LIBRARY}) +add_library(persistence-binding MODULE persistence-binding.c) +target_link_libraries(persistence-binding ${DB_LIBRARY}) -set_target_properties(ll-database-binding PROPERTIES +set_target_properties(persistence-binding PROPERTIES PREFIX "afb-" LABELS "BINDING" LINK_FLAGS ${BINDINGS_LINK_FLAG} OUTPUT_NAME ${TARGET_NAME}) + +install(TARGETS persistence-binding + RUNTIME DESTINATION bin + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib) \ No newline at end of file diff --git a/ll-database-binding/src/ll-database-binding.c b/ll-database-binding/src/ll-database-binding.c deleted file mode 100644 index e08156e..0000000 --- a/ll-database-binding/src/ll-database-binding.c +++ /dev/null @@ -1,469 +0,0 @@ -/* - * Copyright 2017 IoT.bzh - * - * author: Loïc Collignon - * author: Jose Bollo - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include - -#include - -#define AFB_BINDING_VERSION 2 -#include - -#if !defined(TO_STRING_FLAGS) -# if !defined(JSON_C_TO_STRING_NOSLASHESCAPE) -# define JSON_C_TO_STRING_NOSLASHESCAPE (1<<4) -# endif -# define TO_STRING_FLAGS (JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASHESCAPE) -#endif - -#if defined(USE_BERKELEY_DB) -# undef USE_BERKELEY_DB -#endif - -#if defined(USE_GDBM) -# undef USE_GDBM -# define USE_GDBM 1 -# define USE_BERKELEY_DB 0 -#else -# define USE_GDBM 0 -# define USE_BERKELEY_DB 1 -#endif - -// ----- Berkeley database ----- -#if USE_BERKELEY_DB - -#include - -#define DBFILE "ll-database-binding.db" -#define DATA DBT -#define DATA_SET(k,d,s) do{memset((k),0,sizeof*(k));(k)->data=(void*)d;(k)->size=(uint32_t)s;}while(0) -#define DATA_PTR(k) ((void*)((k).data)) -#define DATA_STR(k) ((char*)((k).data)) -#define DATA_SZ(k) ((size_t)((k).size)) - -static DB *database; - -static int xdb_open(const char *path) -{ - int ret; - - ret = db_create(&database, NULL, 0); - if (ret != 0) - { - AFB_ERROR("Failed to create database: %s.", db_strerror(ret)); - return -1; - } - - ret = database->open(database, NULL, path, NULL, DB_BTREE, DB_CREATE, 0600); - if (ret != 0) - { - AFB_ERROR("Failed to open the '%s' database: %s.", path, db_strerror(ret)); - database->close(database, 0); - return -1; - } - return 0; -} - -static void xdb_put(struct afb_req req, DBT *key, DBT *data, int replace) -{ - int ret; - - ret = database->put(database, NULL, key, data, replace ? 0 : DB_NOOVERWRITE); - if (ret == 0) - afb_req_success(req, NULL, NULL); - else - { - AFB_ERROR("can't %s key %s with %s", replace ? "replace" : "insert", DATA_STR(*key), DATA_STR(*data)); - afb_req_fail_f(req, "failed", "%s", db_strerror(ret)); - } -} - -static void xdb_delete(struct afb_req req, DBT *key) -{ - int ret; - - ret = database->del(database, NULL, key, 0); - if (ret == 0) - afb_req_success_f(req, NULL, NULL); - else - { - AFB_ERROR("can't delete key %s", DATA_STR(*key)); - afb_req_fail_f(req, "failed", "%s", db_strerror(ret)); - } - - free(DATA_PTR(key)); -} - -static void verb_read(struct afb_req req) -{ - DATA key; - DATA data; - int ret; - - char value[4096]; - - struct json_object* result; - struct json_object* val; - - - if (get_key(req, &key)) - return; - - AFB_INFO("read: key=%s", DATA_STR(key)); - - memset(&data, 0, sizeof data); - data.data = value; - data.ulen = 4096; - data.flags = DB_DBT_USERMEM; - - ret = database->get(database, NULL, &key, &data, 0); - if (ret == 0) - { - result = json_object_new_object(); - val = json_tokener_parse(DATA_STR(data)); - json_object_object_add(result, "value", val ? val : json_object_new_string(DATA_STR(data))); - - afb_req_success_f(req, result, "db success: read %s=%s.", DATA_STR(key), DATA_STR(data)); - } - else - afb_req_fail_f(req, "Failed to read datas.", "db fail: read %s - %s", DATA_STR(key), db_strerror(ret)); - - free(DATA_PTR(key)); -} - -#endif - -// ----- gdbm database ----- -#if USE_GDBM - -#include -#include - -#define DBFILE "ll-database-binding.dbm" -#define DATA datum -#define DATA_SET(k,d,s) do{(k)->dptr=(char*)d;(k)->dsize=(int)s;}while(0) -#define DATA_PTR(k) ((void*)((k).dptr)) -#define DATA_STR(k) ((char*)((k).dptr)) -#define DATA_SZ(k) ((size_t)((k).dsize)) - -#if GDBM_VERSION_MAJOR > 1 || (GDBM_VERSION_MAJOR == 1 && GDBM_VERSION_MINOR >= 13) -# define IFSYS(yes,no) (gdbm_syserr[gdbm_errno] ? (yes) : (no)) -#else -# define IFSYS(yes,no) (no) -#endif - -static GDBM_FILE database; - -static void onfatal(const char *text) -{ - AFB_ERROR("fatal gdbm message: %s", text); -} - -static int xdb_open(const char *path) -{ - database = gdbm_open(path, 512, GDBM_WRCREAT|GDBM_SYNC, 0600, onfatal); - if (!database) - { - AFB_ERROR("Fail to open/create database: %s%s%s", - gdbm_errlist[gdbm_errno], - IFSYS(", ", ""), - IFSYS(strerror(errno), "")); - return -1; - - } - return 0; -} - -static void xdb_put(struct afb_req req, datum *key, datum *data, int replace) -{ - int ret; - - ret = gdbm_store(database, *key, *data, replace ? GDBM_REPLACE : GDBM_INSERT); - if (ret == 0) - afb_req_success(req, NULL, NULL); - else - { - AFB_ERROR("can't %s key %s with %s: %s%s%s", - replace ? "replace" : "insert", - DATA_STR(*key), - DATA_STR(*data), - gdbm_errlist[gdbm_errno], - IFSYS(", ", ""), - IFSYS(strerror(errno), "")); - afb_req_fail_f(req, "failed", "%s", ret > 0 ? "key already exists" : gdbm_errlist[gdbm_errno]); - } -} - -static void xdb_delete(struct afb_req req, datum *key) -{ - int ret; - - ret = gdbm_delete(database, *key); - if (ret == 0) - afb_req_success_f(req, NULL, NULL); - else - { - AFB_ERROR("can't delete key %s: %s%s%s", - DATA_STR(*key), - gdbm_errlist[gdbm_errno], - IFSYS(", ", ""), - IFSYS(strerror(errno), "")); - afb_req_fail_f(req, "failed", "%s", gdbm_errlist[gdbm_errno]); - } -} - -static void xdb_get(struct afb_req req, datum *key) -{ - struct json_object* obj; - datum result; - - result = gdbm_fetch(database, *key); - if (result.dptr) - { - obj = json_object_new_object(); - json_object_object_add(obj, "value", json_tokener_parse(result.dptr)); - afb_req_success(req, obj, NULL); - free(result.dptr); - } - else - { - AFB_ERROR("can't get key %s: %s%s%s", - DATA_STR(*key), - gdbm_errlist[gdbm_errno], - IFSYS(", ", ""), - IFSYS(strerror(errno), "")); - afb_req_fail_f(req, "failed", "%s", gdbm_errlist[gdbm_errno]); - } -} -#endif - -// ----- Binding's implementations ----- - -/** - * @brief Get the path to the database - */ -static int get_database_path(char *buffer, size_t size) -{ - static const char dbfile[] = DBFILE; - - char *home, *config; - int rc; - - config = secure_getenv("XDG_CONFIG_HOME"); - if (config) - rc = snprintf(buffer, size, "%s/%s", config, dbfile); - else - { - home = secure_getenv("HOME"); - if (home) - rc = snprintf(buffer, size, "%s/.config/%s", home, dbfile); - else - { - uid_t uid = getuid(); - struct passwd *pwd = getpwuid(uid); - if (pwd) - rc = snprintf(buffer, size, "%s/.config/%s", pwd->pw_dir, dbfile); - else - rc = snprintf(buffer, size, "/home/%d/.config/%s", (int)uid, dbfile); - } - } - return rc; -} - -/** - * @brief Initialize the binding. - * @return Exit code, zero if success. - */ -static int ll_database_binding_init() -{ - char path[PATH_MAX]; - int ret; - - ret = get_database_path(path, sizeof path); - if (ret < 0 || (int)ret >= (int)(sizeof path)) - { - AFB_ERROR("Can't compute the database filename"); - return -1; - } - - AFB_INFO("opening database %s", path); - return xdb_open(path); -} - -/** - * Returns the database key for the 'req' - */ -static int get_key(struct afb_req req, DATA *key) -{ - char *appid, *data; - const char *jkey; - - size_t ljkey, lappid, size; - - struct json_object* args; - struct json_object* item; - - /* get the key */ - args = afb_req_json(req); - if (!json_object_object_get_ex(args, "key", &item)) - { - afb_req_fail(req, "no-key", NULL); - return -1; - } - if (!item - || !(jkey = json_object_get_string(item)) - || !(ljkey = strlen(jkey))) - { - afb_req_fail(req, "bad-key", NULL); - return -1; - } - - /* get the appid */ - appid = afb_req_get_application_id(req); -#if 1 - if (!appid) - appid = strdup("#UNKNOWN-APP#"); -#endif - if (!appid) - { - afb_req_fail(req, "bad-context", NULL); - return -1; - } - - /* make the db-key */ - lappid = strlen(appid); - size = lappid + ljkey + 2; - data = realloc(appid, size); - if (!data) - { - free(appid); - afb_req_fail(req, "out-of-memory", NULL); - return -1; - } - data[lappid] = ':'; - memcpy(&data[lappid + 1], jkey, ljkey + 1); - - /* return the key */ - DATA_SET(key, data, size); - return 0; -} - -static void put(struct afb_req req, int replace) -{ - DATA key; - DATA data; - - const char* value; - - struct json_object* args; - struct json_object* item; - - /* get the value */ - args = afb_req_json(req); - if (!json_object_object_get_ex(args, "value", &item)) - { - afb_req_fail(req, "no-value", NULL); - return; - } - value = json_object_to_json_string_ext(item, TO_STRING_FLAGS); - if (!value) - { - afb_req_fail(req, "out-of-memory", NULL); - return; - } - DATA_SET(&data, value, strlen(value) + 1); /* includes the tailing null */ - - /* get the key */ - if (get_key(req, &key)) - return; - - AFB_INFO("put: key=%s, value=%s", DATA_STR(key), DATA_STR(data)); - xdb_put(req, &key, &data, replace); - free(DATA_PTR(key)); -} - -static void verb_insert(struct afb_req req) -{ - put(req, 0); -} - -static void verb_update(struct afb_req req) -{ - put(req, 1); -} - -static void verb_delete(struct afb_req req) -{ - DATA key; - - if (get_key(req, &key)) - return; - - AFB_INFO("delete: key=%s", DATA_STR(key)); - xdb_delete(req, &key); - free(DATA_PTR(key)); -} - -static void verb_read(struct afb_req req) -{ - DATA key; - - if (get_key(req, &key)) - return; - - AFB_INFO("read: key=%s", DATA_STR(key)); - xdb_get(req, &key); - free(DATA_PTR(key)); -} - -// ----- Binding's configuration ----- -/* -static const struct afb_auth ll_database_binding_auths[] = { -}; -*/ - -#define VERB(name_,auth_,info_,sess_) {\ - .verb = #name_, \ - .callback = verb_##name_, \ - .auth = auth_, \ - .info = info_, \ - .session = sess_ } - -static const afb_verb_v2 ll_database_binding_verbs[]= { - VERB(insert, NULL, NULL, AFB_SESSION_NONE_V2), - VERB(update, NULL, NULL, AFB_SESSION_NONE_V2), - VERB(delete, NULL, NULL, AFB_SESSION_NONE_V2), - VERB(read, NULL, NULL, AFB_SESSION_NONE_V2), - { .verb = NULL} -}; - -const struct afb_binding_v2 afbBindingV2 = { - .api = "ll-database", - .specification = NULL, - .verbs = ll_database_binding_verbs, - .preinit = NULL, - .init = ll_database_binding_init, - .onevent = NULL, - .noconcurrency = 0 -}; diff --git a/ll-database-binding/src/persistence-binding.c b/ll-database-binding/src/persistence-binding.c new file mode 100644 index 0000000..6d56309 --- /dev/null +++ b/ll-database-binding/src/persistence-binding.c @@ -0,0 +1,469 @@ +/* + * Copyright 2017 IoT.bzh + * + * author: Loïc Collignon + * author: Jose Bollo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include + +#define AFB_BINDING_VERSION 2 +#include + +#if !defined(TO_STRING_FLAGS) +# if !defined(JSON_C_TO_STRING_NOSLASHESCAPE) +# define JSON_C_TO_STRING_NOSLASHESCAPE (1<<4) +# endif +# define TO_STRING_FLAGS (JSON_C_TO_STRING_PLAIN | JSON_C_TO_STRING_NOSLASHESCAPE) +#endif + +#if defined(USE_BERKELEY_DB) +# undef USE_BERKELEY_DB +#endif + +#if defined(USE_GDBM) +# undef USE_GDBM +# define USE_GDBM 1 +# define USE_BERKELEY_DB 0 +#else +# define USE_GDBM 0 +# define USE_BERKELEY_DB 1 +#endif + +// ----- Berkeley database ----- +#if USE_BERKELEY_DB + +#include + +#define DBFILE "ll-database-binding.db" +#define DATA DBT +#define DATA_SET(k,d,s) do{memset((k),0,sizeof*(k));(k)->data=(void*)d;(k)->size=(uint32_t)s;}while(0) +#define DATA_PTR(k) ((void*)((k).data)) +#define DATA_STR(k) ((char*)((k).data)) +#define DATA_SZ(k) ((size_t)((k).size)) + +static DB *database; + +static int xdb_open(const char *path) +{ + int ret; + + ret = db_create(&database, NULL, 0); + if (ret != 0) + { + AFB_ERROR("Failed to create database: %s.", db_strerror(ret)); + return -1; + } + + ret = database->open(database, NULL, path, NULL, DB_BTREE, DB_CREATE, 0600); + if (ret != 0) + { + AFB_ERROR("Failed to open the '%s' database: %s.", path, db_strerror(ret)); + database->close(database, 0); + return -1; + } + return 0; +} + +static void xdb_put(struct afb_req req, DBT *key, DBT *data, int replace) +{ + int ret; + + ret = database->put(database, NULL, key, data, replace ? 0 : DB_NOOVERWRITE); + if (ret == 0) + afb_req_success(req, NULL, NULL); + else + { + AFB_ERROR("can't %s key %s with %s", replace ? "replace" : "insert", DATA_STR(*key), DATA_STR(*data)); + afb_req_fail_f(req, "failed", "%s", db_strerror(ret)); + } +} + +static void xdb_delete(struct afb_req req, DBT *key) +{ + int ret; + + ret = database->del(database, NULL, key, 0); + if (ret == 0) + afb_req_success_f(req, NULL, NULL); + else + { + AFB_ERROR("can't delete key %s", DATA_STR(*key)); + afb_req_fail_f(req, "failed", "%s", db_strerror(ret)); + } + + free(DATA_PTR(key)); +} + +static void verb_read(struct afb_req req) +{ + DATA key; + DATA data; + int ret; + + char value[4096]; + + struct json_object* result; + struct json_object* val; + + + if (get_key(req, &key)) + return; + + AFB_INFO("read: key=%s", DATA_STR(key)); + + memset(&data, 0, sizeof data); + data.data = value; + data.ulen = 4096; + data.flags = DB_DBT_USERMEM; + + ret = database->get(database, NULL, &key, &data, 0); + if (ret == 0) + { + result = json_object_new_object(); + val = json_tokener_parse(DATA_STR(data)); + json_object_object_add(result, "value", val ? val : json_object_new_string(DATA_STR(data))); + + afb_req_success_f(req, result, "db success: read %s=%s.", DATA_STR(key), DATA_STR(data)); + } + else + afb_req_fail_f(req, "Failed to read datas.", "db fail: read %s - %s", DATA_STR(key), db_strerror(ret)); + + free(DATA_PTR(key)); +} + +#endif + +// ----- gdbm database ----- +#if USE_GDBM + +#include +#include + +#define DBFILE "ll-database-binding.dbm" +#define DATA datum +#define DATA_SET(k,d,s) do{(k)->dptr=(char*)d;(k)->dsize=(int)s;}while(0) +#define DATA_PTR(k) ((void*)((k).dptr)) +#define DATA_STR(k) ((char*)((k).dptr)) +#define DATA_SZ(k) ((size_t)((k).dsize)) + +#if GDBM_VERSION_MAJOR > 1 || (GDBM_VERSION_MAJOR == 1 && GDBM_VERSION_MINOR >= 13) +# define IFSYS(yes,no) (gdbm_syserr[gdbm_errno] ? (yes) : (no)) +#else +# define IFSYS(yes,no) (no) +#endif + +static GDBM_FILE database; + +static void onfatal(const char *text) +{ + AFB_ERROR("fatal gdbm message: %s", text); +} + +static int xdb_open(const char *path) +{ + database = gdbm_open(path, 512, GDBM_WRCREAT|GDBM_SYNC, 0600, onfatal); + if (!database) + { + AFB_ERROR("Fail to open/create database: %s%s%s", + gdbm_errlist[gdbm_errno], + IFSYS(", ", ""), + IFSYS(strerror(errno), "")); + return -1; + + } + return 0; +} + +static void xdb_put(struct afb_req req, datum *key, datum *data, int replace) +{ + int ret; + + ret = gdbm_store(database, *key, *data, replace ? GDBM_REPLACE : GDBM_INSERT); + if (ret == 0) + afb_req_success(req, NULL, NULL); + else + { + AFB_ERROR("can't %s key %s with %s: %s%s%s", + replace ? "replace" : "insert", + DATA_STR(*key), + DATA_STR(*data), + gdbm_errlist[gdbm_errno], + IFSYS(", ", ""), + IFSYS(strerror(errno), "")); + afb_req_fail_f(req, "failed", "%s", ret > 0 ? "key already exists" : gdbm_errlist[gdbm_errno]); + } +} + +static void xdb_delete(struct afb_req req, datum *key) +{ + int ret; + + ret = gdbm_delete(database, *key); + if (ret == 0) + afb_req_success_f(req, NULL, NULL); + else + { + AFB_ERROR("can't delete key %s: %s%s%s", + DATA_STR(*key), + gdbm_errlist[gdbm_errno], + IFSYS(", ", ""), + IFSYS(strerror(errno), "")); + afb_req_fail_f(req, "failed", "%s", gdbm_errlist[gdbm_errno]); + } +} + +static void xdb_get(struct afb_req req, datum *key) +{ + struct json_object* obj; + datum result; + + result = gdbm_fetch(database, *key); + if (result.dptr) + { + obj = json_object_new_object(); + json_object_object_add(obj, "value", json_tokener_parse(result.dptr)); + afb_req_success(req, obj, NULL); + free(result.dptr); + } + else + { + AFB_ERROR("can't get key %s: %s%s%s", + DATA_STR(*key), + gdbm_errlist[gdbm_errno], + IFSYS(", ", ""), + IFSYS(strerror(errno), "")); + afb_req_fail_f(req, "failed", "%s", gdbm_errlist[gdbm_errno]); + } +} +#endif + +// ----- Binding's implementations ----- + +/** + * @brief Get the path to the database + */ +static int get_database_path(char *buffer, size_t size) +{ + static const char dbfile[] = DBFILE; + + char *home, *config; + int rc; + + config = secure_getenv("XDG_CONFIG_HOME"); + if (config) + rc = snprintf(buffer, size, "%s/%s", config, dbfile); + else + { + home = secure_getenv("HOME"); + if (home) + rc = snprintf(buffer, size, "%s/.config/%s", home, dbfile); + else + { + uid_t uid = getuid(); + struct passwd *pwd = getpwuid(uid); + if (pwd) + rc = snprintf(buffer, size, "%s/.config/%s", pwd->pw_dir, dbfile); + else + rc = snprintf(buffer, size, "/home/%d/.config/%s", (int)uid, dbfile); + } + } + return rc; +} + +/** + * @brief Initialize the binding. + * @return Exit code, zero if success. + */ +static int ll_database_binding_init() +{ + char path[PATH_MAX]; + int ret; + + ret = get_database_path(path, sizeof path); + if (ret < 0 || (int)ret >= (int)(sizeof path)) + { + AFB_ERROR("Can't compute the database filename"); + return -1; + } + + AFB_INFO("opening database %s", path); + return xdb_open(path); +} + +/** + * Returns the database key for the 'req' + */ +static int get_key(struct afb_req req, DATA *key) +{ + char *appid, *data; + const char *jkey; + + size_t ljkey, lappid, size; + + struct json_object* args; + struct json_object* item; + + /* get the key */ + args = afb_req_json(req); + if (!json_object_object_get_ex(args, "key", &item)) + { + afb_req_fail(req, "no-key", NULL); + return -1; + } + if (!item + || !(jkey = json_object_get_string(item)) + || !(ljkey = strlen(jkey))) + { + afb_req_fail(req, "bad-key", NULL); + return -1; + } + + /* get the appid */ + appid = afb_req_get_application_id(req); +#if 1 + if (!appid) + appid = strdup("#UNKNOWN-APP#"); +#endif + if (!appid) + { + afb_req_fail(req, "bad-context", NULL); + return -1; + } + + /* make the db-key */ + lappid = strlen(appid); + size = lappid + ljkey + 2; + data = realloc(appid, size); + if (!data) + { + free(appid); + afb_req_fail(req, "out-of-memory", NULL); + return -1; + } + data[lappid] = ':'; + memcpy(&data[lappid + 1], jkey, ljkey + 1); + + /* return the key */ + DATA_SET(key, data, size); + return 0; +} + +static void put(struct afb_req req, int replace) +{ + DATA key; + DATA data; + + const char* value; + + struct json_object* args; + struct json_object* item; + + /* get the value */ + args = afb_req_json(req); + if (!json_object_object_get_ex(args, "value", &item)) + { + afb_req_fail(req, "no-value", NULL); + return; + } + value = json_object_to_json_string_ext(item, TO_STRING_FLAGS); + if (!value) + { + afb_req_fail(req, "out-of-memory", NULL); + return; + } + DATA_SET(&data, value, strlen(value) + 1); /* includes the tailing null */ + + /* get the key */ + if (get_key(req, &key)) + return; + + AFB_INFO("put: key=%s, value=%s", DATA_STR(key), DATA_STR(data)); + xdb_put(req, &key, &data, replace); + free(DATA_PTR(key)); +} + +static void verb_insert(struct afb_req req) +{ + put(req, 0); +} + +static void verb_update(struct afb_req req) +{ + put(req, 1); +} + +static void verb_delete(struct afb_req req) +{ + DATA key; + + if (get_key(req, &key)) + return; + + AFB_INFO("delete: key=%s", DATA_STR(key)); + xdb_delete(req, &key); + free(DATA_PTR(key)); +} + +static void verb_read(struct afb_req req) +{ + DATA key; + + if (get_key(req, &key)) + return; + + AFB_INFO("read: key=%s", DATA_STR(key)); + xdb_get(req, &key); + free(DATA_PTR(key)); +} + +// ----- Binding's configuration ----- +/* +static const struct afb_auth ll_database_binding_auths[] = { +}; +*/ + +#define VERB(name_,auth_,info_,sess_) {\ + .verb = #name_, \ + .callback = verb_##name_, \ + .auth = auth_, \ + .info = info_, \ + .session = sess_ } + +static const afb_verb_v2 ll_database_binding_verbs[]= { + VERB(insert, NULL, NULL, AFB_SESSION_NONE_V2), + VERB(update, NULL, NULL, AFB_SESSION_NONE_V2), + VERB(delete, NULL, NULL, AFB_SESSION_NONE_V2), + VERB(read, NULL, NULL, AFB_SESSION_NONE_V2), + { .verb = NULL} +}; + +const struct afb_binding_v2 afbBindingV2 = { + .api = "persistence", + .specification = NULL, + .verbs = ll_database_binding_verbs, + .preinit = NULL, + .init = ll_database_binding_init, + .onevent = NULL, + .noconcurrency = 0 +}; -- cgit 1.2.3-korg