aboutsummaryrefslogtreecommitdiffstats
path: root/Controler-afb
diff options
context:
space:
mode:
authorfulup <fulup.arfoll@iot.bzh>2017-08-08 18:52:13 +0200
committerfulup <fulup.arfoll@iot.bzh>2017-08-08 18:52:13 +0200
commitf817ce67ff6344f181d221c859e1cb2231a3dac4 (patch)
treeca95512377f7e2105a3a113c31c75abde0dd20ad /Controler-afb
parent33c2cd0236823d108cbb21af34b8d7843d117ac1 (diff)
Early Draft of LUA integration
Diffstat (limited to 'Controler-afb')
-rw-r--r--Controler-afb/CMakeLists.txt60
-rw-r--r--Controler-afb/ctl-apidef.h128
-rw-r--r--Controler-afb/ctl-apidef.json281
-rw-r--r--Controler-afb/ctl-binding.c74
-rw-r--r--Controler-afb/ctl-binding.h96
-rw-r--r--Controler-afb/ctl-events.c139
-rw-r--r--Controler-afb/ctl-lua.c380
-rw-r--r--Controler-afb/ctl-policy.c196
8 files changed, 1354 insertions, 0 deletions
diff --git a/Controler-afb/CMakeLists.txt b/Controler-afb/CMakeLists.txt
new file mode 100644
index 0000000..afebdf2
--- /dev/null
+++ b/Controler-afb/CMakeLists.txt
@@ -0,0 +1,60 @@
+###########################################################################
+# 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.
+###########################################################################
+
+
+# Generate API-v2 hat from OpenAPI json definition
+macro(SET_TARGET_GENSKEL TARGET_NAME API_DEF_NAME)
+ add_custom_command(OUTPUT ${API_DEF_NAME}.h
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ DEPENDS ${API_DEF_NAME}.json
+ COMMAND afb-genskel ${API_DEF_NAME}.json >${API_DEF_NAME}.h
+ )
+ add_custom_target(${API_DEF_NAME}_OPENAPI DEPENDS ${API_DEF_NAME}.h)
+ add_dependencies(${TARGET_NAME} ${API_DEF_NAME}_OPENAPI)
+
+endmacro(SET_TARGET_GENSKEL)
+
+# Add target to project dependency list
+PROJECT_TARGET_ADD(control-afb)
+
+ # Define project Targets
+ ADD_LIBRARY(${TARGET_NAME} MODULE ctl-binding.c ctl-events.c ctl-policy.c ctl-lua.c
+)
+
+ # Generate API-v2 hat from OpenAPI json definition
+ SET_TARGET_GENSKEL(${TARGET_NAME} ctl-apidef)
+
+ # Binder exposes a unique public entry point
+ SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES
+ PREFIX "afb-"
+ LABELS "BINDING"
+ LINK_FLAGS ${BINDINGS_LINK_FLAG}
+ OUTPUT_NAME ${TARGET_NAME}
+
+ )
+
+ # Library dependencies (include updates automatically)
+ TARGET_LINK_LIBRARIES(${TARGET_NAME}
+ audio-common
+ ${link_libraries}
+ )
+
+ # installation directory
+ INSTALL(TARGETS ${TARGET_NAME}
+ LIBRARY DESTINATION ${BINDINGS_INSTALL_DIR})
+
diff --git a/Controler-afb/ctl-apidef.h b/Controler-afb/ctl-apidef.h
new file mode 100644
index 0000000..0ab4cd2
--- /dev/null
+++ b/Controler-afb/ctl-apidef.h
@@ -0,0 +1,128 @@
+
+static const char _afb_description_v2_control[] =
+ "{\"openapi\":\"3.0.0\",\"$schema\":\"http:iot.bzh/download/openapi/schem"
+ "a-3.0/default-schema.json\",\"info\":{\"description\":\"\",\"title\":\"p"
+ "olctl\",\"version\":\"1.0\",\"x-binding-c-generator\":{\"api\":\"control"
+ "\",\"version\":2,\"prefix\":\"ctlapi_\",\"postfix\":\"\",\"start\":null,"
+ "\"onevent\":null,\"init\":\"CtlBindingInit\",\"scope\":\"\",\"private\":"
+ "false}},\"servers\":[{\"url\":\"ws://{host}:{port}/api/polctl\",\"descri"
+ "ption\":\"Unicens2 API.\",\"variables\":{\"host\":{\"default\":\"localho"
+ "st\"},\"port\":{\"default\":\"1234\"}},\"x-afb-events\":[{\"$ref\":\"#/c"
+ "omponents/schemas/afb-event\"}]}],\"components\":{\"schemas\":{\"afb-rep"
+ "ly\":{\"$ref\":\"#/components/schemas/afb-reply-v2\"},\"afb-event\":{\"$"
+ "ref\":\"#/components/schemas/afb-event-v2\"},\"afb-reply-v2\":{\"title\""
+ ":\"Generic response.\",\"type\":\"object\",\"required\":[\"jtype\",\"req"
+ "uest\"],\"properties\":{\"jtype\":{\"type\":\"string\",\"const\":\"afb-r"
+ "eply\"},\"request\":{\"type\":\"object\",\"required\":[\"status\"],\"pro"
+ "perties\":{\"status\":{\"type\":\"string\"},\"info\":{\"type\":\"string\""
+ "},\"token\":{\"type\":\"string\"},\"uuid\":{\"type\":\"string\"},\"reqid"
+ "\":{\"type\":\"string\"}}},\"response\":{\"type\":\"object\"}}},\"afb-ev"
+ "ent-v2\":{\"type\":\"object\",\"required\":[\"jtype\",\"event\"],\"prope"
+ "rties\":{\"jtype\":{\"type\":\"string\",\"const\":\"afb-event\"},\"event"
+ "\":{\"type\":\"string\"},\"data\":{\"type\":\"object\"}}}},\"x-permissio"
+ "ns\":{\"monitor\":{\"permission\":\"urn:AGL:permission:audio:public:moni"
+ "tor\"},\"multimedia\":{\"permission\":\"urn:AGL:permission:audio:public:"
+ "monitor\"},\"navigation\":{\"permission\":\"urn:AGL:permission:audio:pub"
+ "lic:monitor\"},\"emergency\":{\"permission\":\"urn:AGL:permission:audio:"
+ "public:emergency\"}},\"responses\":{\"200\":{\"description\":\"A complex"
+ " object array response\",\"content\":{\"application/json\":{\"schema\":{"
+ "\"$ref\":\"#/components/schemas/afb-reply\"}}}}}},\"paths\":{\"/monitor\""
+ ":{\"description\":\"Subcribe Audio Agent Policy Control End\",\"get\":{\""
+ "x-permissions\":{\"$ref\":\"#/components/x-permissions/monitor\"},\"para"
+ "meters\":[{\"in\":\"query\",\"name\":\"event_patern\",\"required\":true,"
+ "\"schema\":{\"type\":\"string\"}}],\"responses\":{\"200\":{\"$ref\":\"#/"
+ "components/responses/200\"}}}},\"/event_test\":{\"description\":\"Pause "
+ "Resume Test\",\"get\":{\"x-permissions\":{\"$ref\":\"#/components/x-perm"
+ "issions/monitor\"},\"parameters\":[{\"in\":\"query\",\"name\":\"delay\","
+ "\"required\":false,\"schema\":{\"type\":\"interger\"}},{\"in\":\"query\""
+ ",\"name\":\"count\",\"required\":false,\"schema\":{\"type\":\"interger\""
+ "}}],\"responses\":{\"200\":{\"$ref\":\"#/components/responses/200\"}}}},"
+ "\"/navigation\":{\"description\":\"Request Access to Navigation Audio Ch"
+ "annel.\",\"get\":{\"x-permissions\":{\"$ref\":\"#/components/x-permissio"
+ "ns/navigation\"},\"parameters\":[{\"in\":\"query\",\"name\":\"zone\",\"r"
+ "equired\":false,\"schema\":{\"type\":\"string\"}}],\"responses\":{\"200\""
+ ":{\"$ref\":\"#/components/responses/200\"}}}},\"/lua_docall\":{\"descrip"
+ "tion\":\"Execute LUA string script.\",\"get\":{\"x-permissions\":{\"$ref"
+ "\":\"#/components/x-permissions/navigation\"},\"parameters\":[{\"in\":\""
+ "query\",\"name\":\"func\",\"required\":true,\"schema\":{\"type\":\"strin"
+ "g\"}},{\"in\":\"query\",\"name\":\"args\",\"required\":false,\"schema\":"
+ "{\"type\":\"array\"}}],\"responses\":{\"200\":{\"$ref\":\"#/components/r"
+ "esponses/200\"}}}},\"/lua_dostring\":{\"description\":\"Execute LUA stri"
+ "ng script.\",\"get\":{\"x-permissions\":{\"$ref\":\"#/components/x-permi"
+ "ssions/navigation\"},\"parameters\":[{\"in\":\"query\",\"required\":true"
+ ",\"schema\":{\"type\":\"string\"}}],\"responses\":{\"200\":{\"$ref\":\"#"
+ "/components/responses/200\"}}}},\"/lua_doscript\":{\"description\":\"Exe"
+ "cute LUA string script.\",\"get\":{\"x-permissions\":{\"$ref\":\"#/compo"
+ "nents/x-permissions/navigation\"},\"parameters\":[{\"in\":\"query\",\"na"
+ "me\":\"filename\",\"required\":true,\"schema\":{\"type\":\"string\"}}],\""
+ "responses\":{\"200\":{\"$ref\":\"#/components/responses/200\"}}}}}}"
+;
+
+static const struct afb_auth _afb_auths_v2_control[] = {
+ { .type = afb_auth_Permission, .text = "urn:AGL:permission:audio:public:monitor" }
+};
+
+ void ctlapi_monitor(struct afb_req req);
+ void ctlapi_event_test(struct afb_req req);
+ void ctlapi_navigation(struct afb_req req);
+ void ctlapi_lua_docall(struct afb_req req);
+ void ctlapi_lua_dostring(struct afb_req req);
+ void ctlapi_lua_doscript(struct afb_req req);
+
+static const struct afb_verb_v2 _afb_verbs_v2_control[] = {
+ {
+ .verb = "monitor",
+ .callback = ctlapi_monitor,
+ .auth = &_afb_auths_v2_control[0],
+ .info = NULL,
+ .session = AFB_SESSION_NONE_V2
+ },
+ {
+ .verb = "event_test",
+ .callback = ctlapi_event_test,
+ .auth = &_afb_auths_v2_control[0],
+ .info = NULL,
+ .session = AFB_SESSION_NONE_V2
+ },
+ {
+ .verb = "navigation",
+ .callback = ctlapi_navigation,
+ .auth = &_afb_auths_v2_control[0],
+ .info = NULL,
+ .session = AFB_SESSION_NONE_V2
+ },
+ {
+ .verb = "lua_docall",
+ .callback = ctlapi_lua_docall,
+ .auth = &_afb_auths_v2_control[0],
+ .info = NULL,
+ .session = AFB_SESSION_NONE_V2
+ },
+ {
+ .verb = "lua_dostring",
+ .callback = ctlapi_lua_dostring,
+ .auth = &_afb_auths_v2_control[0],
+ .info = NULL,
+ .session = AFB_SESSION_NONE_V2
+ },
+ {
+ .verb = "lua_doscript",
+ .callback = ctlapi_lua_doscript,
+ .auth = &_afb_auths_v2_control[0],
+ .info = NULL,
+ .session = AFB_SESSION_NONE_V2
+ },
+ { .verb = NULL }
+};
+
+const struct afb_binding_v2 afbBindingV2 = {
+ .api = "control",
+ .specification = _afb_description_v2_control,
+ .info = NULL,
+ .verbs = _afb_verbs_v2_control,
+ .preinit = NULL,
+ .init = CtlBindingInit,
+ .onevent = NULL,
+ .noconcurrency = 0
+};
+
diff --git a/Controler-afb/ctl-apidef.json b/Controler-afb/ctl-apidef.json
new file mode 100644
index 0000000..fddf301
--- /dev/null
+++ b/Controler-afb/ctl-apidef.json
@@ -0,0 +1,281 @@
+{
+ "openapi": "3.0.0",
+ "$schema": "http:iot.bzh/download/openapi/schema-3.0/default-schema.json",
+ "info": {
+ "description": "",
+ "title": "polctl",
+ "version": "1.0",
+ "x-binding-c-generator": {
+ "api": "control",
+ "version": 2,
+ "prefix": "ctlapi_",
+ "postfix": "",
+ "start": null,
+ "onevent": null,
+ "init": "CtlBindingInit",
+ "scope": "",
+ "private": false
+ }
+ },
+ "servers": [
+ {
+ "url": "ws://{host}:{port}/api/polctl",
+ "description": "Unicens2 API.",
+ "variables": {
+ "host": {
+ "default": "localhost"
+ },
+ "port": {
+ "default": "1234"
+ }
+ },
+ "x-afb-events": [
+ {
+ "$ref": "#/components/schemas/afb-event"
+ }
+ ]
+ }
+ ],
+ "components": {
+ "schemas": {
+ "afb-reply": {
+ "$ref": "#/components/schemas/afb-reply-v2"
+ },
+ "afb-event": {
+ "$ref": "#/components/schemas/afb-event-v2"
+ },
+ "afb-reply-v2": {
+ "title": "Generic response.",
+ "type": "object",
+ "required": ["jtype", "request"],
+ "properties": {
+ "jtype": {
+ "type": "string",
+ "const": "afb-reply"
+ },
+ "request": {
+ "type": "object",
+ "required": ["status"],
+ "properties": {
+ "status": {
+ "type": "string"
+ },
+ "info": {
+ "type": "string"
+ },
+ "token": {
+ "type": "string"
+ },
+ "uuid": {
+ "type": "string"
+ },
+ "reqid": {
+ "type": "string"
+ }
+ }
+ },
+ "response": {
+ "type": "object"
+ }
+ }
+ },
+ "afb-event-v2": {
+ "type": "object",
+ "required": ["jtype", "event"],
+ "properties": {
+ "jtype": {
+ "type": "string",
+ "const": "afb-event"
+ },
+ "event": {
+ "type": "string"
+ },
+ "data": {
+ "type": "object"
+ }
+ }
+ }
+ },
+ "x-permissions": {
+ "monitor": {
+ "permission": "urn:AGL:permission:audio:public:monitor"
+ },
+ "multimedia": {
+ "permission": "urn:AGL:permission:audio:public:monitor"
+ },
+ "navigation": {
+ "permission": "urn:AGL:permission:audio:public:monitor"
+ },
+ "emergency": {
+ "permission": "urn:AGL:permission:audio:public:emergency"
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "A complex object array response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/afb-reply"
+ }
+ }
+ }
+ }
+ }
+ },
+ "paths": {
+ "/monitor": {
+ "description": "Subcribe Audio Agent Policy Control End",
+ "get": {
+ "x-permissions": {
+ "$ref": "#/components/x-permissions/monitor"
+ },
+ "parameters": [
+ {
+ "in": "query",
+ "name": "event_patern",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "$ref": "#/components/responses/200"
+ }
+ }
+ }
+ },
+ "/event_test": {
+ "description": "Pause Resume Test",
+ "get": {
+ "x-permissions": {
+ "$ref": "#/components/x-permissions/monitor"
+ },
+ "parameters": [
+ {
+ "in": "query",
+ "name": "delay",
+ "required": false,
+ "schema": {
+ "type": "interger"
+ }
+ },
+ {
+ "in": "query",
+ "name": "count",
+ "required": false,
+ "schema": {
+ "type": "interger"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "$ref": "#/components/responses/200"
+ }
+ }
+ }
+ },
+ "/navigation": {
+ "description": "Request Access to Navigation Audio Channel.",
+ "get": {
+ "x-permissions": {
+ "$ref": "#/components/x-permissions/navigation"
+ },
+ "parameters": [
+ {
+ "in": "query",
+ "name": "zone",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "$ref": "#/components/responses/200"
+ }
+ }
+ }
+ },
+ "/lua_docall": {
+ "description": "Execute LUA string script.",
+ "get": {
+ "x-permissions": {
+ "$ref": "#/components/x-permissions/navigation"
+ },
+ "parameters": [
+ {
+ "in": "query",
+ "name": "func",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "in": "query",
+ "name": "args",
+ "required": false,
+ "schema": {
+ "type": "array"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "$ref": "#/components/responses/200"
+ }
+ }
+ }
+ },
+ "/lua_dostring": {
+ "description": "Execute LUA string script.",
+ "get": {
+ "x-permissions": {
+ "$ref": "#/components/x-permissions/navigation"
+ },
+ "parameters": [
+ {
+ "in": "query",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "$ref": "#/components/responses/200"
+ }
+ }
+ }
+ },
+ "/lua_doscript": {
+ "description": "Execute LUA string script.",
+ "get": {
+ "x-permissions": {
+ "$ref": "#/components/x-permissions/navigation"
+ },
+ "parameters": [
+ {
+ "in": "query",
+ "name": "filename",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "$ref": "#/components/responses/200"
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/Controler-afb/ctl-binding.c b/Controler-afb/ctl-binding.c
new file mode 100644
index 0000000..45c4e1c
--- /dev/null
+++ b/Controler-afb/ctl-binding.c
@@ -0,0 +1,74 @@
+/*
+ * 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, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include "audio-common.h"
+#include "ctl-binding.h"
+
+
+
+// Include Binding Stub generated from Json OpenAPI
+#include "ctl-apidef.h"
+
+
+PUBLIC void ctlapi_navigation (afb_req request) {
+
+ ctlapi_authorize (CTLAPI_NAVIGATION, request);
+}
+
+PUBLIC void ctlapi_multimedia (afb_req request) {
+
+ ctlapi_authorize (CTLAPI_MULTIMEDIA, request);
+}
+
+PUBLIC void ctlapi_emergency (afb_req request) {
+
+ ctlapi_authorize (CTLAPI_EMERGENCY, request);
+}
+
+PUBLIC void ctlapi_monitor (afb_req request) {
+
+ // subscribe Client to event
+ int err = afb_req_subscribe(request, TimerEvtGet());
+ if (err != 0) {
+ afb_req_fail_f(request, "register-event", "Fail to subscribe binder event");
+ goto OnErrorExit;
+ }
+
+ afb_req_success(request, NULL, NULL);
+
+ OnErrorExit:
+ return;
+}
+
+// Create Binding Event at Init
+PUBLIC int CtlBindingInit () {
+
+ int errcount=0;
+
+ errcount += TimerEvtInit();
+ errcount += PolicyInit();
+ errcount += LuaLibInit();
+
+ AFB_DEBUG ("Audio Policy Control Binding Done errcount=%d", errcount);
+ return errcount;
+}
+
diff --git a/Controler-afb/ctl-binding.h b/Controler-afb/ctl-binding.h
new file mode 100644
index 0000000..e53d2ca
--- /dev/null
+++ b/Controler-afb/ctl-binding.h
@@ -0,0 +1,96 @@
+/*
+ * 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, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <systemd/sd-event.h>
+
+#include "audio-common.h"
+
+#ifndef CONTROLER_BINDING_INCLUDE
+#define CONTROLER_BINDING_INCLUDE
+
+// polctl-binding.c
+PUBLIC int CtlBindingInit ();
+
+// ctl-timerevt.c
+// ----------------------
+#define DEFAULT_PAUSE_DELAY 3000
+#define DEFAULT_TEST_COUNT 1
+typedef int (*timerCallbackT)(void *context);
+typedef struct {
+ int value;
+ const char *label;
+} AutoTestCtxT;
+
+typedef struct TimerHandleS {
+ int count;
+ int delay;
+ AutoTestCtxT *context;
+ timerCallbackT callback;
+ sd_event_source *evtSource;
+} TimerHandleT;
+
+PUBLIC int TimerEvtInit (void);
+PUBLIC afb_event TimerEvtGet(void);
+PUBLIC void ctlapi_event_test (afb_req request);
+
+// ctl-policy
+// -----------
+
+typedef struct PolicyActionS{
+ const char* label;
+ const char* api;
+ const char* verb;
+ json_object *argsJ;
+ const char *info;
+ int timeout;
+ json_object* (*actionCB)(struct PolicyActionS *action,json_object *response, void *context);
+} PolicyActionT;
+
+typedef struct {
+ const char* label;
+ const char *info;
+ const char *version;
+ void *context;
+} PolicyHandleT;
+
+typedef struct {
+ char *sharelib;
+ void *dlHandle;
+ PolicyHandleT **handle;
+ PolicyActionT **onload;
+ PolicyActionT **events;
+ PolicyActionT **controls;
+} PolicyCtlConfigT;
+
+typedef enum {
+ CTLAPI_NAVIGATION,
+ CTLAPI_MULTIMEDIA,
+ CTLAPI_EMERGENCY,
+
+ CTL_NONE=-1
+} PolicyCtlEnumT;
+
+PUBLIC int PolicyInit(void);
+PUBLIC json_object* ScanForConfig (char* searchPath, char * pre, char *ext);
+PUBLIC void ctlapi_authorize (PolicyCtlEnumT control, afb_req request);
+
+// ctl-lua.c
+PUBLIC int LuaLibInit ();
+PUBLIC void ctlapi_lua_docall (afb_req request);
+PUBLIC void ctlapi_lua_dostring (afb_req request);
+PUBLIC void ctlapi_lua_doscript (afb_req request);
+
+#endif
diff --git a/Controler-afb/ctl-events.c b/Controler-afb/ctl-events.c
new file mode 100644
index 0000000..f444848
--- /dev/null
+++ b/Controler-afb/ctl-events.c
@@ -0,0 +1,139 @@
+/*
+ * 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, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <systemd/sd-event.h>
+
+#include "ctl-binding.h"
+
+static afb_event afbevt;
+
+STATIC int TimerNext (sd_event_source* source, uint64_t timer, void* handle) {
+ TimerHandleT *timerHandle = (TimerHandleT*) handle;
+ int done;
+ uint64_t usec;
+
+ // Rearm timer if needed
+ timerHandle->count --;
+ if (timerHandle->count == 0) sd_event_source_unref(source);
+ else {
+ // otherwise validate timer for a new run
+ sd_event_now(afb_daemon_get_event_loop(), CLOCK_MONOTONIC, &usec);
+ sd_event_source_set_enabled(source, SD_EVENT_ONESHOT);
+ sd_event_source_set_time(source, usec + timerHandle->delay);
+ }
+
+ done= timerHandle->callback(timerHandle->context);
+ if (!done) goto OnErrorExit;
+
+ return 0;
+
+OnErrorExit:
+ AFB_WARNING("TimerNext Callback Fail Tag=%s", timerHandle->context->label);
+ return -1;
+}
+
+
+STATIC int DoSendEvent (void *context) {
+ AutoTestCtxT *ctx= (AutoTestCtxT*)context;
+ json_object *ctlEventJ;
+
+ if (ctx->value) ctx->value =0;
+ else ctx->value =1;
+
+ ctlEventJ = json_object_new_object();
+ json_object_object_add(ctlEventJ,"action", json_object_new_string(ctx->label));
+ json_object_object_add(ctlEventJ,"value" , json_object_new_int(ctx->value));
+ int done = afb_event_push(afbevt, ctlEventJ);
+
+ AFB_NOTICE ("DoSendEvent {action: '%s', value:%d} status=%d", ctx->label, ctx->value, done);
+
+ return (done);
+}
+
+STATIC void TimerEvtStart(TimerHandleT *timerHandle, void *context) {
+ uint64_t usec;
+
+ // populate CB handle
+ timerHandle->callback=DoSendEvent;
+ timerHandle->context=context;
+
+ // set a timer with ~250us accuracy
+ sd_event_now(afb_daemon_get_event_loop(), CLOCK_MONOTONIC, &usec);
+ sd_event_add_time(afb_daemon_get_event_loop(), &timerHandle->evtSource, CLOCK_MONOTONIC, usec+timerHandle->delay, 250, TimerNext, timerHandle);
+}
+
+PUBLIC afb_event TimerEvtGet(void) {
+ return afbevt;
+}
+
+
+// Generated some fake event based on watchdog/counter
+PUBLIC void ctlapi_event_test (afb_req request) {
+ json_object *queryJ, *tmpJ;
+ TimerHandleT *timerHandle = malloc (sizeof (TimerHandleT));
+ AutoTestCtxT *context = calloc (1, sizeof (AutoTestCtxT));
+ int done;
+
+ queryJ= afb_req_json(request);
+
+ // Closing call only has one parameter
+ done=json_object_object_get_ex(queryJ, "closing", &tmpJ);
+ if (done) return;
+
+ done=json_object_object_get_ex(queryJ, "label", &tmpJ);
+ if (!done) {
+ afb_req_fail_f(request, "TEST-LABEL-MISSING", "label is mandatory for event_test");
+ goto OnErrorExit;
+ }
+ context->label = strdup(json_object_get_string (tmpJ));
+
+ json_object_object_get_ex(queryJ, "delay", &tmpJ);
+ timerHandle->delay = json_object_get_int (tmpJ) * 1000;
+ if (timerHandle->delay == 0) timerHandle->delay=DEFAULT_PAUSE_DELAY * 1000;
+
+ json_object_object_get_ex(queryJ, "count", &tmpJ);
+ timerHandle->count = json_object_get_int (tmpJ);
+ if (timerHandle->count == 0) timerHandle->count=DEFAULT_TEST_COUNT;
+
+ // start a lool timer
+ TimerEvtStart (timerHandle, context);
+
+ afb_req_success(request, NULL, NULL);
+ return;
+
+ OnErrorExit:
+ return;
+}
+
+// Create Binding Event at Init
+PUBLIC int TimerEvtInit () {
+
+ // create binder event to send test pause/resume
+ afbevt = afb_daemon_make_event("request");
+ if (!afb_event_is_valid(afbevt)) {
+ AFB_ERROR ("POLCTL_INIT: Cannot register ctl-events");
+ return 1;
+ }
+
+ AFB_DEBUG ("Audio Control-Events Init Done");
+ return 0;
+}
+
diff --git a/Controler-afb/ctl-lua.c b/Controler-afb/ctl-lua.c
new file mode 100644
index 0000000..0e44bc9
--- /dev/null
+++ b/Controler-afb/ctl-lua.c
@@ -0,0 +1,380 @@
+/*
+ * 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, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ref:
+ * http://www.troubleshooters.com/codecorn/lua/lua_c_calls_lua.htm#_Anatomy_of_a_Lua_Call
+ * http://acamara.es/blog/2012/08/passing-variables-from-lua-5-2-to-c-and-vice-versa/
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <string.h>
+#include <dirent.h>
+
+#include "lua.h"
+#include "lauxlib.h"
+#include "lualib.h"
+
+#include "ctl-binding.h"
+#include "wrap-json.h"
+
+
+static lua_State* luaState;
+
+typedef enum {
+ LUA_DOCALL,
+ LUA_DOSTRING,
+ LUA_DOSCRIPT,
+} LuaDoActionT;
+
+// List Avaliable Configuration Files
+PUBLIC json_object* ScanForConfig (char* searchPath, char *pre, char *ext) {
+ json_object *responseJ;
+ DIR *dirHandle;
+ char *dirPath;
+ char* dirList= strdup(searchPath);
+ size_t extLen = strlen(ext);
+
+ responseJ = json_object_new_array();
+ for (dirPath= strtok(dirList, ":"); dirPath && *dirPath; dirPath=strtok(NULL,":")) {
+ struct dirent *dirEnt;
+
+ dirHandle = opendir (dirPath);
+ if (!dirHandle) {
+ AFB_NOTICE ("CONFIG-SCANNING dir=%s not readable", dirPath);
+ continue;
+ }
+
+ AFB_NOTICE ("CONFIG-SCANNING:ctl_listconfig scanning: %s", dirPath);
+ while ((dirEnt = readdir(dirHandle)) != NULL) {
+ // Unknown type is accepted to support dump filesystems
+ if (dirEnt->d_type == DT_REG || dirEnt->d_type == DT_UNKNOWN) {
+
+ // check prefix and extention
+ size_t extIdx=strlen(dirEnt->d_name) - extLen;
+ if (extIdx <= 0) continue;
+ if (pre && !strcasestr (dirEnt->d_name, pre)) continue;
+ if (ext && strcasecmp (ext, &dirEnt->d_name[extIdx])) continue;
+
+ struct json_object *pathJ = json_object_new_object();
+ json_object_object_add(pathJ, "dirpath", json_object_new_string(dirPath));
+ json_object_object_add(pathJ, "filename", json_object_new_string(dirEnt->d_name));
+ json_object_array_add(responseJ, pathJ);
+ }
+ }
+ }
+
+ free (dirList);
+ return (responseJ);
+}
+
+STATIC int LuaPrintNotice(lua_State* luaState) {
+ int count = lua_gettop(luaState);
+
+ for (int idx=1; idx <= count; ++idx) {
+ const char *str = lua_tostring(luaState, idx); // Get string
+
+ // Output string.
+ AFB_NOTICE (str);
+ }
+
+ return 0; // no value return
+}
+
+STATIC int LuaPushArgument (json_object *arg) {
+
+ switch (json_object_get_type(arg)) {
+ case json_type_object:
+ lua_newtable (luaState);
+ json_object_object_foreach (arg, key, val) {
+ int done = LuaPushArgument (val);
+ if (done) {
+ lua_pushstring(luaState, key); // table.key = val
+ lua_settable(luaState, -3);
+ }
+ }
+
+ break;
+ case json_type_int:
+ lua_pushinteger(luaState, json_object_get_int(arg));
+ break;
+ case json_type_string:
+ lua_pushstring(luaState, json_object_get_string(arg));
+ break;
+ case json_type_boolean:
+ lua_pushboolean(luaState, json_object_get_boolean(arg));
+ break;
+ case json_type_double:
+ lua_pushnumber(luaState, json_object_get_double(arg));
+ break;
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+// Generated some fake event based on watchdog/counter
+PUBLIC void LuaDoAction (LuaDoActionT action, afb_req request) {
+
+ int err, count=0;
+
+ json_object* queryJ = afb_req_json(request);
+
+ switch (action) {
+
+ case LUA_DOSTRING: {
+ const char *script = json_object_get_string(queryJ);
+ err=luaL_loadstring(luaState, script);
+ if (err) {
+ AFB_ERROR ("LUA-DO-COMPILE:FAIL String=%s err=%s", script, lua_tostring(luaState,-1) );
+ goto OnErrorExit;
+ }
+ break;
+ }
+
+ case LUA_DOCALL: {
+ const char *func;
+ json_object *args;
+ err= wrap_json_unpack (queryJ, "{s:s, s?o !}", "func", &func,"args", &args);
+ if (err) {
+ AFB_ERROR ("LUA-DOCALL-SYNTAX missing func|args args=%s", json_object_get_string(queryJ));
+ goto OnErrorExit;
+ }
+
+ // load function (should exist in CONTROL_PATH_LUA
+ lua_getglobal(luaState, func);
+
+ // push arguments on the stack
+ if (json_object_get_type(args) != json_type_array) {
+ count= LuaPushArgument (args);
+ } else {
+ for (int idx=0; idx<json_object_array_length(args); idx++) {
+ count += LuaPushArgument (json_object_array_get_idx(args, idx));
+ if (err) break;
+ }
+ }
+
+ break;
+ }
+
+ case LUA_DOSCRIPT: {
+ const char *script;
+ json_object *args;
+ int index;
+
+ // scan luascript search path once
+ static json_object *luaScriptPathJ =NULL;
+ if (!luaScriptPathJ) luaScriptPathJ= ScanForConfig(CONTROL_PATH_LUA , NULL, "lua");
+
+ err= wrap_json_unpack (queryJ, "{s:s, s?o s?o !}", "script", &script,"args", &args, "arg", &args);
+ if (err) {
+ AFB_ERROR ("LUA-DOCALL-SYNTAX missing script|(args,arg) args=%s", json_object_get_string(queryJ));
+ goto OnErrorExit;
+ }
+
+ // push arguments on the stack
+ if (json_object_get_type(args) != json_type_array) {
+ lua_createtable(luaState, 1, 0);
+ count= LuaPushArgument (args);
+ } else {
+ int length= json_object_array_length(args);
+ lua_createtable(luaState, length, 0);
+ for (int idx=0; idx < length; idx++) {
+ count += LuaPushArgument (json_object_array_get_idx(args, idx));
+ if (err) break;
+ }
+ }
+
+ for (index=0; index < json_object_array_length(luaScriptPathJ); index++) {
+ char *filename; char*dirpath;
+ json_object *entryJ=json_object_array_get_idx(luaScriptPathJ, index);
+
+ err= wrap_json_unpack (entryJ, "{s:s, s:s !}", "dirpath", &dirpath,"filename", &filename);
+ if (err) {
+ AFB_ERROR ("LUA-DOSCRIPT HOOPs invalid LUA script path = %s", json_object_get_string(entryJ));
+ goto OnErrorExit;
+ }
+
+ if (strcmp(filename, script)) continue;
+
+ char filepath[255];
+ strncpy(filepath, dirpath, sizeof(filepath));
+ strncat(filepath, "/", sizeof(filepath));
+ strncat(filepath, filename, sizeof(filepath));
+ err= luaL_loadfile(luaState, filepath);
+ if (err) {
+ AFB_ERROR ("LUA-DOSCRIPT HOOPs Error in LUA loading scripts=%s err=%s", filepath, lua_tostring(luaState,-1));
+ goto OnErrorExit;
+ }
+ break;
+ }
+
+ if (index == json_object_array_length(luaScriptPathJ)) {
+ AFB_ERROR ("LUA-DOSCRIPT HOOPs script=%s not in path=%s", script, CONTROL_PATH_LUA);
+ goto OnErrorExit;
+
+ }
+
+ //lua_setglobal(luaState, "args");
+ count=1;
+
+ break;
+ }
+
+ default:
+ AFB_ERROR ("LUA-DOCALL-ACTION unknown query=%s", json_object_get_string(queryJ));
+ goto OnErrorExit;
+ }
+
+ // effectively exec LUA code
+// err=lua_pcall(luaState, count, LUA_MULTRET, 0);
+ err=lua_pcall(luaState, count, LUA_MULTRET, 0);
+ if (err) {
+ AFB_ERROR ("LUA-DO-EXEC:FAIL query=%s err=%s", json_object_get_string(queryJ), lua_tostring(luaState,-1) );
+ goto OnErrorExit;
+ }
+
+ // number of return values
+ count=lua_gettop(luaState);
+
+ // Check status return true=OK false=fail
+ if (count == 0 || !lua_isboolean(luaState, 1)) {
+ AFB_ERROR ("LUA-DO-RETURN:INVALID 1st return argument not boolean query=%s", json_object_get_string(queryJ) );
+ goto OnErrorExit;
+ }
+
+ // get return fail/ok status
+ const int returnStatus=lua_toboolean(luaState, 1);
+
+ // loop on remaining return arguments
+ json_object *returnArgs = json_object_new_array();
+ for (int idx=2; idx <= count; idx++) {
+
+ // push on stack return value (Fulup in LUA-5.3 the two functions are combined)
+ int valueType=lua_type (luaState, idx);
+
+ switch(valueType) {
+ case LUA_TNUMBER:
+ json_object_array_add(returnArgs, json_object_new_double(lua_tonumber(luaState, idx)));
+ break;
+ case LUA_TBOOLEAN:
+ json_object_array_add(returnArgs, json_object_new_boolean(lua_toboolean(luaState, idx)));
+ break;
+ case LUA_TSTRING:
+ json_object_array_add(returnArgs, json_object_new_string(lua_tostring(luaState, idx)));
+ break;
+ case LUA_TTABLE:
+ default:
+ AFB_NOTICE ("script returned Unknown/Unsupported type: ");
+ }
+
+ }
+
+ // pop stack including Func/String/Script call
+ lua_pop(luaState, count+1);
+
+ if(returnStatus)
+ afb_req_success(request, returnArgs, NULL);
+ else
+ afb_req_fail(request, "LUA-DOACTION-FAIL", json_object_get_string(returnArgs));
+
+ return;
+
+ OnErrorExit:
+ afb_req_fail(request,"LUA:ERROR", lua_tostring(luaState,-1));
+ return;
+}
+
+PUBLIC void ctlapi_lua_dostring (afb_req request) {
+
+ LuaDoAction (LUA_DOSTRING, request);
+}
+
+PUBLIC void ctlapi_lua_docall (afb_req request) {
+
+ LuaDoAction (LUA_DOCALL, request);
+}
+
+PUBLIC void ctlapi_lua_doscript (afb_req request) {
+
+ LuaDoAction (LUA_DOSCRIPT, request);
+}
+
+
+// Create Binding Event at Init
+PUBLIC int LuaLibInit () {
+ int err, index;
+
+ // search for default policy config file
+ json_object *luaScriptPathJ = ScanForConfig(CONTROL_PATH_LUA , "onload", "lua");
+
+ // open a new LUA interpretor
+ luaState = luaL_newstate();
+ if (!luaState) {
+ AFB_ERROR ("LUA_INIT: Fail to open lua interpretor");
+ goto OnErrorExit;
+ }
+
+ // load auxiliary libraries
+ luaL_openlibs(luaState);
+
+ // redirect print to AFB_NOTICE
+ lua_register(luaState,"print", LuaPrintNotice );
+ //lua_register(lauHandle,"AFB_DEBUG", LuaAFBDebug);
+
+ // load+exec any file found in LUA search path
+ for (index=0; index < json_object_array_length(luaScriptPathJ); index++) {
+ json_object *entryJ=json_object_array_get_idx(luaScriptPathJ, index);
+
+ char *filename; char*dirpath;
+ err= wrap_json_unpack (entryJ, "{s:s, s:s !}", "dirpath", &dirpath,"filename", &filename);
+ if (err) {
+ AFB_ERROR ("LUA-INIT HOOPs invalid config file path = %s", json_object_get_string(entryJ));
+ goto OnErrorExit;
+ }
+
+ char filepath[255];
+ strncpy(filepath, dirpath, sizeof(filepath));
+ strncat(filepath, "/", sizeof(filepath));
+ strncat(filepath, filename, sizeof(filepath));
+ err= luaL_loadfile(luaState, filepath);
+ if (err) {
+ AFB_ERROR ("LUA-LOAD HOOPs Error in LUA loading scripts=%s err=%s", filepath, lua_tostring(luaState,-1));
+ goto OnErrorExit;
+ }
+
+ // exec/compil script
+ err = lua_pcall(luaState, 0, 0, 0);
+ if (err) {
+ AFB_ERROR ("LUA-LOAD HOOPs Error in LUA exec scripts=%s err=%s", filepath, lua_tostring(luaState,-1));
+ goto OnErrorExit;
+ }
+
+ }
+
+ // no policy config found remove control API from binder
+ if (index == 0) {
+ AFB_WARNING ("POLICY-INIT:WARNING No Control LUA file in path=[%s]", CONTROL_PATH_LUA);
+ }
+
+
+ AFB_DEBUG ("Audio control-LUA Init Done");
+ return 0;
+
+ OnErrorExit:
+ return -1;
+}
+ \ No newline at end of file
diff --git a/Controler-afb/ctl-policy.c b/Controler-afb/ctl-policy.c
new file mode 100644
index 0000000..7ad73fa
--- /dev/null
+++ b/Controler-afb/ctl-policy.c
@@ -0,0 +1,196 @@
+/*
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <string.h>
+
+#include <json-c/json_object.h>
+
+#include "wrap-json.h"
+#include "ctl-binding.h"
+
+STATIC PolicyCtlConfigT *ctlHandle = NULL;
+
+
+PUBLIC void ctlapi_authorize (PolicyCtlEnumT 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_PATH_POLICY);
+ AFB_NOTICE ("CONFIG-MISSING: use default CONTROL_PATH_POLICY=%s", CONTROL_PATH_POLICY);
+ }
+
+ // 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_PATH_POLICY");
+ } else {
+ afb_req_success(request, responseJ, NULL);
+ }
+
+ return;
+}
+
+STATIC PolicyActionT *PolicyLoadActions (json_object *actionsJ) {
+ int err;
+ PolicyActionT *actions;
+ char *callback; // need to search in DL lib
+
+ // unpack individual action object
+ int actionUnpack (json_object *actionJ, PolicyActionT *action) {
+
+ err= wrap_json_unpack(actionJ, "{ss,s?s,s?o,s?s,s?s,s?s !}"
+ , "label",&action->label, "info",&action->info, "callback",&callback, "args",&action->argsJ, "api",&action->api, "verb", &action->verb);
+ if (err) {
+ AFB_ERROR ("POLICY-LOAD-ACTION Missing something label|info|callback|api|verb|args in %s", json_object_get_string(actionJ));
+ return -1;
+ }
+ if (!callback || !(action->api && action->verb)) {
+ AFB_ERROR ("POLICY-LOAD-ACTION Missing something callback|(api+verb) in %s", json_object_get_string(actionJ));
+ return -1;
+ }
+ return 0;
+ };
+
+ // 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(PolicyActionT));
+
+ for (int idx=0; idx < count; idx++) {
+ json_object *actionJ = json_object_array_get_idx(actionsJ, idx);
+ err = actionUnpack (actionJ, &actions[idx]);
+ if (err) goto OnErrorExit;
+ }
+
+ } else {
+ actions = calloc (2, sizeof(PolicyActionT));
+ err = actionUnpack (actionsJ, &actions[0]);
+ if (err) goto OnErrorExit;
+ }
+
+ return actions;
+
+ OnErrorExit:
+ return NULL;
+
+}
+
+// load control policy from file using json_unpack https://jansson.readthedocs.io/en/2.9/apiref.html#parsing-and-validating-values
+STATIC PolicyCtlConfigT *PolicyLoadConfig (const char* filepath) {
+ json_object *policyConfigJ, *ignoreJ, *actionsJ;
+ PolicyCtlConfigT *policyConfig = calloc (1, sizeof(PolicyCtlConfigT));
+ int err;
+
+ // Load JSON file
+ policyConfigJ= json_object_from_file(filepath);
+ if (!policyConfigJ) goto OnErrorExit;
+
+ json_object *metadataJ, *onloadJ, *controlsJ, *eventsJ;
+ err= wrap_json_unpack(policyConfigJ, "{s?o,so,s?o,so,so !}", "$schema", &ignoreJ, "metadata",&metadataJ, "onload",&onloadJ, "controls",&controlsJ, "events",&eventsJ);
+ if (err) {
+ AFB_ERROR ("POLICY-LOAD-ERRROR Missing something metadata|onload|controls|events in %s", json_object_get_string(policyConfigJ));
+ goto OnErrorExit;
+ }
+
+ PolicyHandleT *policyHandle = calloc (1, sizeof(PolicyHandleT));
+ err= wrap_json_unpack(metadataJ, "{so,s?s,s?s !}", "label", &policyHandle->label, "info",&policyHandle->info, "version",&policyHandle->version);
+ if (err) {
+ AFB_ERROR ("POLICY-LOAD-CONFIG Missing something label|info|version in %s", json_object_get_string(metadataJ));
+ goto OnErrorExit;
+ }
+
+ if (onloadJ) {
+ err= wrap_json_unpack(onloadJ, "{s?o,s?s,s?s !}", "info",&ignoreJ, "label",&ignoreJ, "actions",&actionsJ);
+ if (err) {
+ AFB_ERROR ("POLICY-LOAD-CONFIG Missing something label|info|plugin|actions in %s", json_object_get_string(metadataJ));
+ goto OnErrorExit;
+ }
+ policyConfig->onload= PolicyLoadActions (actionsJ);
+ }
+
+ return policyConfig;
+
+OnErrorExit:
+ return NULL;
+}
+
+// Load default config file at init
+PUBLIC int PolicyInit () {
+ int index, err;
+
+
+ // search for default policy config file
+ json_object* responseJ = ScanForConfig(CONTROL_PATH_POLICY, "onload", "json");
+ return 0;
+
+ 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 ("POLICY-INIT HOOPs invalid config file path = %s", json_object_get_string(entryJ));
+ goto OnErrorExit;
+ }
+
+ if (strcasestr(filename, CONTROL_FILE_POLICY)) {
+ char filepath[255];
+ strncpy(filepath, dirpath, sizeof(filepath));
+ strncat(filepath, "/", sizeof(filepath));
+ strncat(filepath, filename, sizeof(filepath));
+ ctlHandle = PolicyLoadConfig (filepath);
+ if (!ctlHandle) {
+ AFB_ERROR ("POLICY-INIT:ERROR No File to load [%s]", filepath);
+ goto OnErrorExit;
+ }
+ break;
+ }
+ }
+
+ // no policy config found remove control API from binder
+ if (index == 0) {
+ AFB_WARNING ("POLICY-INIT:WARNING No Control policy file [%s]", CONTROL_FILE_POLICY);
+ }
+
+ AFB_NOTICE ("POLICY-INIT:SUCCES: Audio Control Policy Init");
+ return 0;
+
+OnErrorExit:
+ AFB_NOTICE ("POLICY-INIT:ERROR: Audio Control Policy Init");
+ return 1;
+}
+
+
+