summaryrefslogtreecommitdiffstats
path: root/Controler-afb/ctl-dispatch.c
diff options
context:
space:
mode:
Diffstat (limited to 'Controler-afb/ctl-dispatch.c')
-rw-r--r--Controler-afb/ctl-dispatch.c318
1 files changed, 318 insertions, 0 deletions
diff --git a/Controler-afb/ctl-dispatch.c b/Controler-afb/ctl-dispatch.c
new file mode 100644
index 0000000..cda3431
--- /dev/null
+++ b/Controler-afb/ctl-dispatch.c
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) 2016 "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, something express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Reference:
+ * Json load using json_unpack https://jansson.readthedocs.io/en/2.9/apiref.html#parsing-and-validating-values
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <string.h>
+#include <dlfcn.h>
+
+
+#include <json-c/json_object.h>
+
+#include "wrap-json.h"
+#include "ctl-binding.h"
+
+
+typedef struct {
+ const char* label;
+ const char *info;
+ const char *version;
+ DispatchActionT *actions;
+} DispatchHandleT;
+
+
+typedef struct {
+ const char* label;
+ const char *info;
+ const char *version;
+ char *plugin;
+ void *dlHandle;
+ DispatchHandleT *onload;
+ DispatchHandleT *events;
+ DispatchHandleT *controls;
+} DispatchConfigT;
+
+STATIC DispatchConfigT *ctlHandle = NULL;
+
+PUBLIC void ctlapi_dispatch (DispatchCtlEnumT control, afb_req request) {
+ json_object*tmpJ;
+
+ json_object* argsJ= afb_req_json(request);
+ int done=json_object_object_get_ex(argsJ, "closing", &tmpJ);
+ if (done) return;
+
+}
+
+// List Avaliable Configuration Files
+PUBLIC void ctlapi_config (struct afb_req request) {
+ json_object*tmpJ;
+ char *dirList;
+
+ json_object* argsJ = afb_req_json(request);
+ if (argsJ && json_object_object_get_ex (argsJ, "cfgpath" , &tmpJ)) {
+ dirList = strdup (json_object_get_string(tmpJ));
+ } else {
+ dirList = strdup (CONTROL_DISPATCH_PATH);
+ AFB_NOTICE ("CONFIG-MISSING: use default CONTROL_DISPATCH_PATH=%s", CONTROL_DISPATCH_PATH);
+ }
+
+ // get list of config file
+ struct json_object *responseJ = ScanForConfig(dirList, "onload", "json");
+
+ if (json_object_array_length(responseJ) == 0) {
+ afb_req_fail(request, "CONFIGPATH:EMPTY", "No Config Found in CONTROL_DISPATCH_PATH");
+ } else {
+ afb_req_success(request, responseJ, NULL);
+ }
+
+ return;
+}
+
+// unpack individual action object
+STATIC int DispatchLoadOneAction (json_object *actionJ, DispatchActionT *action) {
+ char *api, *verb, *callback, *lua;
+ int err, modeCount=0;
+
+ err= wrap_json_unpack(actionJ, "{ss,s?s,s?s,s?o,s?s,s?s,s?s !}"
+ , "label",&action->label, "info",&action->info, "callback",&callback, "lua", &lua, "args",&action->argsJ, "api",&api, "verb", &verb);
+ if (err) {
+ AFB_ERROR ("DISPATCH-LOAD-ACTION Missing something label|info|callback|lua|(api+verb)|args in %s", json_object_get_string(actionJ));
+ goto OnErrorExit;
+ }
+
+ if (lua) {
+ action->mode = CTL_MODE_LUA;
+ action->call=lua;
+ modeCount++;
+ }
+
+ if (api && verb) {
+ action->mode = CTL_MODE_API;
+ action->api=api;
+ action->call=verb;
+ modeCount++;
+ }
+
+ if (callback) {
+ action->mode = CTL_MODE_CB;
+ action->call=callback;
+ modeCount++;
+
+ action->actionCB = dlsym(ctlHandle->dlHandle, callback);
+ if (!action->actionCB) {
+ AFB_ERROR ("DISPATCH-LOAD-ACTION fail to find calbback=%s in %s", callback, ctlHandle->plugin);
+ goto OnErrorExit;
+ }
+ }
+
+ // make sure at least one mode is selected
+ if (modeCount == 0) {
+ AFB_ERROR ("DISPATCH-LOAD-ACTION Missing something lua|callback|(api+verb) in %s", json_object_get_string(actionJ));
+ goto OnErrorExit;
+ }
+
+ if (modeCount > 1) {
+ AFB_ERROR ("DISPATCH-LOAD-ACTION ToMany lua|callback|(api+verb) in %s", json_object_get_string(actionJ));
+ goto OnErrorExit;
+ }
+ return 0;
+
+OnErrorExit:
+ return -1;
+};
+
+STATIC DispatchActionT *DispatchLoadActions (json_object *actionsJ) {
+ int err;
+ DispatchActionT *actions;
+
+ // action array is close with a nullvalue;
+ if (json_object_get_type(actionsJ) == json_type_array) {
+ int count = json_object_array_length(actionsJ);
+ actions = calloc (count+1, sizeof(DispatchActionT));
+
+ for (int idx=0; idx < count; idx++) {
+ json_object *actionJ = json_object_array_get_idx(actionsJ, idx);
+ err = DispatchLoadOneAction (actionJ, &actions[idx]);
+ if (err) goto OnErrorExit;
+ }
+
+ } else {
+ actions = calloc (2, sizeof(DispatchActionT));
+ err = DispatchLoadOneAction (actionsJ, &actions[0]);
+ if (err) goto OnErrorExit;
+ }
+
+ return actions;
+
+ OnErrorExit:
+ return NULL;
+
+}
+
+STATIC DispatchConfigT *DispatchLoadConfig (const char* filepath) {
+ json_object *dispatchConfigJ, *ignoreJ;
+ int err;
+
+ // Load JSON file
+ dispatchConfigJ= json_object_from_file(filepath);
+ if (!dispatchConfigJ) goto OnErrorExit;
+
+ AFB_INFO ("DISPATCH-LOAD-CONFIG: loading config filepath=%s", filepath);
+
+ json_object *metadataJ=NULL, *onloadJ=NULL, *controlsJ=NULL, *eventsJ=NULL;
+ err= wrap_json_unpack(dispatchConfigJ, "{s?o,so,s?o,s?o,s?o !}", "$schema", &ignoreJ, "metadata",&metadataJ, "onload",&onloadJ, "controls",&controlsJ, "events",&eventsJ);
+ if (err) {
+ AFB_ERROR ("DISPATCH-LOAD-CONFIG Missing something metadata|[onload]|[controls]|[events] in %s", json_object_get_string(dispatchConfigJ));
+ goto OnErrorExit;
+ }
+
+ DispatchConfigT *dispatchConfig = calloc (1, sizeof(DispatchConfigT));
+ if (metadataJ) {
+ err= wrap_json_unpack(metadataJ, "{so,s?s,ss !}", "label", &dispatchConfig->label, "info",&dispatchConfig->info, "version",&dispatchConfig->version);
+ if (err) {
+ AFB_ERROR ("DISPATCH-LOAD-CONFIG:METADATA Missing something label|version|[label] in %s", json_object_get_string(metadataJ));
+ goto OnErrorExit;
+ }
+ }
+
+ if (onloadJ) {
+ json_object * actionsJ;
+ DispatchHandleT *dispatchHandle = calloc (1, sizeof(DispatchHandleT));
+
+ err= wrap_json_unpack(onloadJ, "{so,s?s,s?s,s?o !}", "label",&dispatchHandle->label, "info",&dispatchHandle->info, "plugin", &dispatchConfig->plugin, "actions",&actionsJ);
+ if (err) {
+ AFB_ERROR ("DISPATCH-LOAD-CONFIG:ONLOAD Missing something label|[info]|[plugin]|[actions] in %s", json_object_get_string(onloadJ));
+ goto OnErrorExit;
+ }
+
+ if (dispatchConfig->plugin) {
+
+ // search for default policy config file
+ json_object *pluginPathJ = ScanForConfig(CONTROL_PLUGIN_PATH , dispatchConfig->plugin, NULL);
+ if (!pluginPathJ || json_object_array_length(pluginPathJ) == 0) {
+ AFB_ERROR ("DISPATCH-LOAD-CONFIG:PLUGIN Missing plugin=%s in path=%s", dispatchConfig->plugin, CONTROL_PLUGIN_PATH);
+ goto OnErrorExit;
+ }
+
+ char *filename; char*dirpath;
+ err= wrap_json_unpack (json_object_array_get_idx(pluginPathJ,1), "{s:s, s:s !}", "dirpath", &dirpath,"filename", &filename);
+ if (err) {
+ AFB_ERROR ("DISPATCH-LOAD-CONFIG:PLUGIN HOOPs invalid plugin file path = %s", json_object_get_string(pluginPathJ));
+ goto OnErrorExit;
+ }
+
+ if (json_object_array_length(pluginPathJ) > 1) {
+ AFB_WARNING ("DISPATCH-LOAD-CONFIG:PLUGIN plugin multiple instances in searchpath will use %s/%s", dirpath, filepath);
+ }
+
+ char filepath[255];
+ strncpy(filepath, dirpath, sizeof(filepath));
+ strncat(filepath, "/", sizeof(filepath));
+ strncat(filepath, filename, sizeof(filepath));
+ dispatchConfig->dlHandle = dlopen(filepath, RTLD_NOW);
+ if (!dispatchConfig->dlHandle) {
+ AFB_ERROR ("DISPATCH-LOAD-CONFIG:PLIUGIN Fail to load filepath=%s err= %s", filepath, dlerror());
+ goto OnErrorExit;
+ }
+ }
+
+ dispatchHandle->actions= DispatchLoadActions(actionsJ);
+ dispatchConfig->onload= dispatchHandle;
+ }
+
+ if (controlsJ) {
+ json_object * actionsJ;
+ DispatchHandleT *dispatchHandle = calloc (1, sizeof(DispatchHandleT));
+
+ err= wrap_json_unpack(controlsJ, "{so,s?s,so !}", "label",&dispatchHandle->label, "info",&dispatchHandle->info, "actions",&actionsJ);
+ if (err) {
+ AFB_ERROR ("DISPATCH-LOAD-CONFIG:CONTROLS Missing something label|[info]|actions in %s", json_object_get_string(controlsJ));
+ goto OnErrorExit;
+ }
+ dispatchHandle->actions= DispatchLoadActions(actionsJ);
+ dispatchConfig->onload= dispatchHandle;
+ }
+
+ if (eventsJ) {
+ json_object * actionsJ;
+ DispatchHandleT *dispatchHandle = calloc (1, sizeof(DispatchHandleT));
+
+ err= wrap_json_unpack(eventsJ, "{so,s?s,so !}", "label",&dispatchHandle->label, "info",&dispatchHandle->info, "actions",&actionsJ);
+ if (err) {
+ AFB_ERROR ("DISPATCH-LOAD-CONFIG:EVENTS Missing something label|[info]|actions in %s", json_object_get_string(eventsJ));
+ goto OnErrorExit;
+ }
+ dispatchHandle->actions= DispatchLoadActions(actionsJ);
+ dispatchConfig->onload= dispatchHandle;
+ }
+
+ return dispatchConfig;
+
+OnErrorExit:
+ return NULL;
+}
+
+// Load default config file at init
+PUBLIC int DispatchInit () {
+ int index, err;
+
+
+ // search for default dispatch config file
+ json_object* responseJ = ScanForConfig(CONTROL_DISPATCH_PATH, "onload", "json");
+
+ for (index=0; index < json_object_array_length(responseJ); index++) {
+ json_object *entryJ=json_object_array_get_idx(responseJ, index);
+
+ char *filename; char*dirpath;
+ err= wrap_json_unpack (entryJ, "{s:s, s:s !}", "dirpath", &dirpath,"filename", &filename);
+ if (err) {
+ AFB_ERROR ("DISPATCH-INIT HOOPs invalid config file path = %s", json_object_get_string(entryJ));
+ goto OnErrorExit;
+ }
+
+ if (strcasestr(filename, CONTROL_DISPATCH_FILE)) {
+ char filepath[255];
+ strncpy(filepath, dirpath, sizeof(filepath));
+ strncat(filepath, "/", sizeof(filepath));
+ strncat(filepath, filename, sizeof(filepath));
+ ctlHandle = DispatchLoadConfig (filepath);
+ if (!ctlHandle) {
+ AFB_ERROR ("DISPATCH-INIT:ERROR No File to load [%s]", filepath);
+ goto OnErrorExit;
+ }
+ break;
+ }
+ }
+
+ // no dispatch config found remove control API from binder
+ if (index == 0) {
+ AFB_WARNING ("DISPATCH-INIT:WARNING No Control dispatch file [%s]", CONTROL_DISPATCH_FILE);
+ }
+
+ AFB_NOTICE ("DISPATCH-INIT:SUCCES: Audio Control Dispatch Init");
+ return 0;
+
+OnErrorExit:
+ AFB_NOTICE ("DISPATCH-INIT:ERROR: Audio Control Dispatch Init");
+ return 1;
+}
+
+
+