aboutsummaryrefslogtreecommitdiffstats
path: root/ll-store-binding
diff options
context:
space:
mode:
Diffstat (limited to 'll-store-binding')
-rw-r--r--ll-store-binding/CMakeLists.txt2
-rw-r--r--ll-store-binding/conf.d/cmake/config.cmake149
-rw-r--r--ll-store-binding/src/CMakeLists.txt16
-rw-r--r--ll-store-binding/src/export.map1
-rw-r--r--ll-store-binding/src/ll-store-binding.c269
-rwxr-xr-xll-store-binding/start.sh3
-rwxr-xr-xll-store-binding/store.sh23
7 files changed, 463 insertions, 0 deletions
diff --git a/ll-store-binding/CMakeLists.txt b/ll-store-binding/CMakeLists.txt
new file mode 100644
index 0000000..0f2f8a9
--- /dev/null
+++ b/ll-store-binding/CMakeLists.txt
@@ -0,0 +1,2 @@
+cmake_minimum_required(VERSION 3.3)
+include(${CMAKE_CURRENT_SOURCE_DIR}/conf.d/cmake/config.cmake)
diff --git a/ll-store-binding/conf.d/cmake/config.cmake b/ll-store-binding/conf.d/cmake/config.cmake
new file mode 100644
index 0000000..c4bd78c
--- /dev/null
+++ b/ll-store-binding/conf.d/cmake/config.cmake
@@ -0,0 +1,149 @@
+###########################################################################
+# Copyright 2015, 2016, 2017 IoT.bzh
+#
+# author: Fulup Ar Foll <fulup@iot.bzh>
+#
+# 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.
+###########################################################################
+
+# Project Info
+# ------------------
+set(PROJECT_NAME ll-store-binding)
+set(PROJECT_VERSION "0.1")
+set(PROJECT_PRETTY_NAME "Low Level Store Binding")
+set(PROJECT_DESCRIPTION "Binding able to store and retrieve data by user/app/tag.")
+set(PROJECT_URL "")
+set(PROJECT_ICON "icon.png")
+set(PROJECT_AUTHOR "Collignon, Loïc")
+set(PROJECT_AUTHOR_MAIL "loic.collignon@iot.bzh")
+set(PROJECT_LICENSE "Apache-V2")
+set(PROJECT_LANGUAGES,"C")
+
+# Where are stored default templates files from submodule or subtree app-templates in your project tree
+# relative to the root project directory
+set(PROJECT_APP_TEMPLATES_DIR "conf.d/app-templates")
+
+# Where are stored your external libraries for your project. This is 3rd party library that you don't maintain
+# but used and must be built and linked.
+# set(PROJECT_LIBDIR "libs")
+
+# Where are stored data for your application. Pictures, static resources must be placed in that folder.
+# set(PROJECT_RESOURCES "data")
+
+# Which directories inspect to find CMakeLists.txt target files
+# set(PROJECT_SRC_DIR_PATTERN "*")
+
+# Compilation Mode (DEBUG, RELEASE)
+# ----------------------------------
+set(CMAKE_BUILD_TYPE "DEBUG")
+
+# Kernel selection if needed. Impose a minimal version.
+# NOTE FOR NOW IT CHECKS KERNEL Yocto SDK Kernel version
+# else only HOST VERSION
+# -----------------------------------------------
+#set (kernel_minimal_version 4.8)
+
+# Compiler selection if needed. Impose a minimal version.
+# -----------------------------------------------
+set (gcc_minimal_version 4.9)
+
+# PKG_CONFIG required packages
+# -----------------------------
+set (PKG_REQUIRED_LIST
+ json-c
+ libsystemd>=222
+ afb-daemon
+ libmicrohttpd>=0.9.55
+)
+
+# Static constante definition
+# -----------------------------
+add_compile_options()
+
+# LANG Specific compile flags set for all build types
+set(CMAKE_C_FLAGS "")
+set(CMAKE_CXX_FLAGS "")
+
+# Print a helper message when every thing is finished
+# ----------------------------------------------------
+#set(CLOSING_MESSAGE "")
+#set(PACKAGE_MESSAGE "Install widget file using in the target : afm-util install ${PROJECT_NAME}.wgt")
+
+# (BUG!!!) as PKG_CONFIG_PATH does not work [should be an env variable]
+# ---------------------------------------------------------------------
+set(CMAKE_INSTALL_PREFIX $ENV{HOME}/opt)
+set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${CMAKE_INSTALL_PREFIX}/lib64/pkgconfig ${CMAKE_INSTALL_PREFIX}/lib/pkgconfig)
+set(LD_LIBRARY_PATH ${CMAKE_INSTALL_PREFIX}/lib64 ${CMAKE_INSTALL_PREFIX}/lib)
+
+# Optional location for config.xml.in
+# -----------------------------------
+#set(WIDGET_CONFIG_TEMPLATE ${CMAKE_CURRENT_SOURCE_DIR}/conf.d/config.xml.in)
+
+# Mandatory widget Mimetype specification of the main unit
+# --------------------------------------------------------------------------
+# Choose between :
+#- text/html : HTML application,
+# content.src designates the home page of the application
+#
+#- application/vnd.agl.native : AGL compatible native,
+# content.src designates the relative path of the binary.
+#
+# - application/vnd.agl.service: AGL service, content.src is not used.
+#
+#- ***application/x-executable***: Native application,
+# content.src designates the relative path of the binary.
+# For such application, only security setup is made.
+#
+set(WIDGET_TYPE MimeType_Not_Set)
+
+# Mandatory Widget entry point file of the main unit
+# --------------------------------------------------------------
+# This is the file that will be executed, loaded,
+# at launch time by the application framework.
+#
+set(WIDGET_ENTRY_POINT EntryPoint_Path_Not_Set)
+
+# Optional dependencies order
+# ---------------------------
+#set(EXTRA_DEPENDENCIES_ORDER)
+
+# Optional Extra global include path
+# -----------------------------------
+#set(EXTRA_INCLUDE_DIRS)
+
+# Optional extra libraries
+# -------------------------
+#set(EXTRA_LINK_LIBRARIES)
+
+# Optional force binding installation
+# ------------------------------------
+# set(BINDINGS_INSTALL_PREFIX PrefixPath )
+
+# Optional force binding Linking flag
+# ------------------------------------
+# set(BINDINGS_LINK_FLAG LinkOptions )
+
+# Optional force package prefix generation, like widget
+# -----------------------------------------------------
+# set(PKG_PREFIX DestinationPath)
+
+# Optional Application Framework security token
+# and port use for remote debugging.
+#------------------------------------------------------------
+#set(AFB_TOKEN "" CACHE PATH "Default AFB_TOKEN")
+#set(AFB_REMPORT "1234" CACHE PATH "Default AFB_TOKEN")
+
+# This include is mandatory and MUST happens at the end
+# of this file, else you expose you to unexpected behavior
+# -----------------------------------------------------------
+include(${PROJECT_APP_TEMPLATES_DIR}/cmake/common.cmake)
diff --git a/ll-store-binding/src/CMakeLists.txt b/ll-store-binding/src/CMakeLists.txt
new file mode 100644
index 0000000..b447f98
--- /dev/null
+++ b/ll-store-binding/src/CMakeLists.txt
@@ -0,0 +1,16 @@
+PROJECT_TARGET_ADD(ll-store-binding)
+
+list(APPEND link_libraries "/usr/lib64/liblmdb.so")
+add_library(ll-store-binding MODULE ll-store-binding.c)
+
+set_target_properties(ll-store-binding PROPERTIES
+ PREFIX "afb-"
+ LABELS "BINDING"
+ LINK_FLAGS ${BINDINGS_LINK_FLAG}
+ OUTPUT_NAME ${TARGET_NAME})
+
+target_link_libraries(ll-store-binding ${link_libraries})
+
+install(
+ TARGETS ll-store-binding
+ LIBRARY DESTINATION ${BINDINGS_INSTALL_DIR})
diff --git a/ll-store-binding/src/export.map b/ll-store-binding/src/export.map
new file mode 100644
index 0000000..ee2f413
--- /dev/null
+++ b/ll-store-binding/src/export.map
@@ -0,0 +1 @@
+{ global: afbBindingV*; local: *; };
diff --git a/ll-store-binding/src/ll-store-binding.c b/ll-store-binding/src/ll-store-binding.c
new file mode 100644
index 0000000..fd65552
--- /dev/null
+++ b/ll-store-binding/src/ll-store-binding.c
@@ -0,0 +1,269 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <string.h>
+#include <json-c/json.h>
+#include <lmdb.h>
+
+#define AFB_BINDING_VERSION 2
+#include <afb/afb-binding.h>
+
+#define DB_FILE "/home/agl/projects/ll-store-binding/build/src/ll-store-binding.lmdb"
+
+MDB_env* dbenv;
+
+/// @brief Get a string from a json object.
+/// @param[in] obj Json object from wich the string is queried.
+/// @param[in] name Name of the string to get.
+/// @return
+const char* get_json_string(struct json_object* obj, const char* name)
+{
+ if (!obj || !name || !strlen(name)) return NULL;
+
+ struct json_object* item = NULL;
+ if (!json_object_object_get_ex(obj, name, &item) || !item) return NULL;
+
+ return json_object_get_string(item);
+}
+
+char* make_key(const char* username, const char* appname, const char* tagname)
+{
+ size_t sz_username = username ? strlen(username) : 0;
+ size_t sz_appname = appname ? strlen(appname) : 0;
+ size_t sz_tagname = tagname ? strlen(tagname) : 0;
+ size_t sz_total = sz_username + sz_appname + sz_tagname + 3;
+
+ char* result = (char*)malloc(sz_total);
+ memset(result, sz_total, 0);
+
+ strcpy(result, username);
+ result[sz_username] = '.';
+
+ strcpy(result + sz_username + 1, appname);
+ result[sz_username + 1 + sz_appname] = '.';
+
+ strcpy(result + sz_username + 1 + sz_appname + 1, tagname);
+
+ return result;
+}
+
+static void verb_get(struct afb_req req)
+{
+ int r;
+ struct json_object* args = afb_req_json(req);
+
+ AFB_INFO("args:\n%s\n", json_object_to_json_string_ext(args, JSON_C_TO_STRING_PRETTY));
+
+ const char* username = get_json_string(args, "username");
+ const char* appname = get_json_string(args, "appname");
+ const char* tagname = get_json_string(args, "tagname");
+
+ if (!username || !appname || !tagname)
+ {
+ AFB_ERROR("[store] username, appname and tagname must be provided!");
+ afb_req_fail(req, "username, appname and tagname must be provided!", NULL);
+ return;
+ }
+
+ char* keyname = make_key(username, appname, tagname);
+
+ MDB_txn* txn;
+ r = mdb_txn_begin(dbenv, NULL, 0, &txn);
+ if (r)
+ {
+ free(keyname);
+ AFB_ERROR("Failed to begin a transaction!");
+ afb_req_fail(req, "Failed to begin a transaction!", NULL);
+ return;
+ }
+
+ MDB_dbi dbi;
+ r = mdb_dbi_open(txn, NULL, 0, &dbi);
+ if (r)
+ {
+ free(keyname);
+ mdb_txn_abort(txn);
+ AFB_ERROR("Failed to open the database!");
+ afb_req_fail(req, "Failed to open the database!", NULL);
+ return;
+ }
+
+ MDB_val k;
+ MDB_val v;
+ k.mv_size = strlen(keyname) + 1;
+ k.mv_data = keyname;
+
+ if(mdb_get(txn, dbi, &k, &v))
+ {
+ free(keyname);
+ mdb_txn_abort(txn);
+ mdb_dbi_close(dbenv, dbi);
+ AFB_ERROR("Failed to get the data!");
+ afb_req_fail(req, "Failed to get the data!", NULL);
+ return;
+ }
+
+ char* value = strndup(v.mv_data, v.mv_size + 1);
+ if(mdb_txn_commit(txn))
+ {
+ free(keyname);
+ free(value);
+ mdb_dbi_close(dbenv, dbi);
+ AFB_ERROR("Failed to commit the transaction!");
+ return;
+ }
+
+ json_object* result = json_object_new_object();
+ json_object_object_add(result, "key", json_object_new_string(keyname));
+ json_object_object_add(result, "value", json_object_new_string(value));
+ afb_req_success(req, result, NULL);
+
+ free(value);
+ free(keyname);
+ return;
+}
+
+static void verb_set(struct afb_req req)
+{
+ int r;
+ struct json_object* args = afb_req_json(req);
+
+ AFB_INFO("args:\n%s\n", json_object_to_json_string_ext(args, JSON_C_TO_STRING_PRETTY));
+
+ const char* username = get_json_string(args, "username");
+ const char* appname = get_json_string(args, "appname");
+ const char* tagname = get_json_string(args, "tagname");
+ const char* value = get_json_string(args, "value");
+
+ if (!username || !appname || !tagname)
+ {
+ AFB_ERROR("[store] username, appname and tagname must be provided!");
+ afb_req_fail(req, "username, appname and tagname must be provided!", NULL);
+ return;
+ }
+
+ char* keyname = make_key(username, appname, tagname);
+
+ MDB_txn* txn;
+ r = mdb_txn_begin(dbenv, NULL, 0, &txn);
+ if (r)
+ {
+ free(keyname);
+ AFB_ERROR("Failed to begin a transaction!");
+ afb_req_fail(req, "Failed to begin a transaction!", NULL);
+ return;
+ }
+
+ MDB_dbi dbi;
+ r = mdb_dbi_open(txn, NULL, 0, &dbi);
+ if (r)
+ {
+ free(keyname);
+ mdb_txn_abort(txn);
+ AFB_ERROR("Failed to open the database!");
+ afb_req_fail(req, "Failed to open the database!", NULL);
+ return;
+ }
+
+ MDB_val k;
+ MDB_val v;
+ k.mv_size = strlen(keyname) + 1;
+ k.mv_data = keyname;
+ v.mv_size = value ? strlen(value) + 1 : 0;
+ v.mv_data = value;
+
+ if(mdb_put(txn, dbi, &k, &v, 0))
+ {
+ free(keyname);
+ mdb_txn_abort(txn);
+ mdb_dbi_close(dbenv, dbi);
+ AFB_ERROR("Failed to get the data!");
+ afb_req_fail(req, "Failed to get the data!", NULL);
+ return;
+ }
+
+ if(mdb_txn_commit(txn))
+ {
+ free(keyname);
+ mdb_dbi_close(dbenv, dbi);
+ AFB_ERROR("Failed to commit the transaction!");
+ return;
+ }
+
+ json_object* result = json_object_new_object();
+ json_object_object_add(result, "key", json_object_new_string(keyname));
+ json_object_object_add(result, "value", json_object_new_string(value));
+ afb_req_success(req, result, NULL);
+
+ free(keyname);
+ return;
+}
+
+int ll_store_preinit()
+{
+ int r = mdb_env_create(&dbenv);
+ if (r)
+ {
+ AFB_INFO("Failed to create MDB environment!");
+ dbenv = NULL;
+ return r;
+ }
+
+ r = mdb_env_open(dbenv, "/home/agl/ll-store-binding.lmdb", MDB_NOSUBDIR, 0644);
+ if (r)
+ {
+ mdb_env_close(dbenv);
+ dbenv = NULL;
+ AFB_INFO("Failed to open MDB environment!");
+ return r;
+ }
+
+/*
+ MDB_txn* txn;
+ r = mdb_txn_begin(dbenv, NULL, 0, &txn);
+ if (r)
+ {
+ mdb_env_close(dbenv);
+ dbenv = NULL;
+ AFB_INFO("Failed to begin a transaction!");
+ return r;
+ }
+
+ MDB_dbi dbi;
+ r = mdb_dbi_open(txn, NULL, 0, &dbi);
+ if (r)
+ {
+ mdb_env_close(dbenv);
+ AFB_INFO("Failed to open the database!");
+ dbenv = NULL;
+ }
+*/
+ return 0;
+}
+
+static const afb_verb_v2 _ll_store_binding_verbs[]= {
+ {
+ .verb = "get",
+ .callback = verb_get,
+ .auth = NULL,
+ .info = NULL,
+ .session = AFB_SESSION_NONE_V2
+ },
+ {
+ .verb = "set",
+ .callback = verb_set,
+ .auth = NULL,
+ .info = NULL,
+ .session = AFB_SESSION_NONE_V2
+ },
+ { .verb=NULL}
+};
+
+const struct afb_binding_v2 afbBindingV2 = {
+ .api = "ll-store",
+ .specification = NULL,
+ .verbs = _ll_store_binding_verbs,
+ .preinit = ll_store_preinit,
+ .init = NULL,
+ .onevent = NULL,
+ .noconcurrency = 0
+};
diff --git a/ll-store-binding/start.sh b/ll-store-binding/start.sh
new file mode 100755
index 0000000..936400b
--- /dev/null
+++ b/ll-store-binding/start.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+afb-daemon --port=9001 --token='' --binding=/home/agl/projects/ll-store-binding/build/src/afb-ll-store-binding.so --verbose
diff --git a/ll-store-binding/store.sh b/ll-store-binding/store.sh
new file mode 100755
index 0000000..d2dfbc7
--- /dev/null
+++ b/ll-store-binding/store.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+case "$1" in
+ "get")
+ if [ "$#" -ne "4" ]; then
+ echo "Usage: store get <user> <app> <tag>"
+ exit 1
+ fi
+ curl -v "http://localhost:9001/api/ll-store/get?username=$2&appname=$3&tagname=$4&token="
+ ;;
+ "set")
+ if [ "$#" -ne "5" ]; then
+ echo "Usage: store get <user> <app> <tag> <value>"
+ exit 1
+ fi
+ curl -v "http://localhost:9001/api/ll-store/set?username=$2&appname=$3&tagname=$4&value=$5&token="
+ ;;
+ *)
+ echo "Usage: store <action> <user> <app> <tag> <value>"
+ echo " Action can be 'get' or 'set'."
+ ;;
+esac
+