diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..567609b1234a9b8806c5a05da6c866e480aa148d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..15472c37baa5b37ccb96802d32cb1c0d610f4dce --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,28 @@ +cmake_minimum_required(VERSION 2.8) +project(dap_chain_plugins_python C) + +set(CMAKE_VERBOSE_MAKEFILE ON) +set(CMAKE_COLOR_MAKEFILE ON) +set(CMAKE_C_STANDARD 11) +add_definitions("-fpic") +add_definitions("-DDAP_LOG_MT") + +if(UNIX) + add_definitions("-DDAP_OS_UNIX") +endif() + +file(GLOB CHAIN_PLUGINS_PYTHON_SRCS src/*.c) +file(GLOB CHAIN_PLUGINS_PYTHON_HEADERS include/*.h) + +set(Python_ADDITIONAL_VERSIONS 3.7 3.6 3.5 3.4) +find_package (PythonLibs REQUIRED) +include_directories(${PYTHON_INCLUDE_DIR} include/) + +add_library(${PROJECT_NAME} STATIC ${CHAIN_PLUGINS_PYTHON_SRCS} ${CHAIN_PLUGINS_PYTHON_HEADERS}) + +target_link_libraries(${PROJECT_NAME}) + +target_link_libraries(${PROJECT_NAME} dap_core ) + +target_include_directories(${PROJECT_NAME} PUBLIC include/ ) + diff --git a/include/dap_chain_plugins.h b/include/dap_chain_plugins.h new file mode 100644 index 0000000000000000000000000000000000000000..fd98781da6dd4b767061bd004bbe623cea78cba8 --- /dev/null +++ b/include/dap_chain_plugins.h @@ -0,0 +1,30 @@ +#ifndef _DAP_CHAIN_PLUGINS_ +#define _DAP_CHAIN_PLUGINS_ +#include <Python.h> +#include "dap_config.h" +#include "dap_common.h" +#include "dap_file_utils.h" +#include "dap_chain_plugins_manifest.h" +#include "dap_chain_plugins_list.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +#undef LOG_TAG +#define LOG_TAG "dap_chain_plugins" + +static PyObject *sys_path; + +const char *plugins_root_path; + +int dap_chain_plugins_init(); +void dap_chain_plugins_deinit(); +void dap_chain_plugins_loading(); +void dap_chain_plugins_load_plugin(const char *dir_path, const char *name); + +#ifdef __cplusplus +} +#endif + +#endif //_DAP_CHAIN_PLUGINS_ diff --git a/include/dap_chain_plugins_list.h b/include/dap_chain_plugins_list.h new file mode 100644 index 0000000000000000000000000000000000000000..0231547ad02378bdfd817b909dc31015ec8e30b3 --- /dev/null +++ b/include/dap_chain_plugins_list.h @@ -0,0 +1,41 @@ +#ifndef _DAP_CHAIN_PLUGINS_LIST_ +#define _DAP_CHAIN_PLUGINS_LIST_ + +#include "Python.h" +#include "stdbool.h" +//#include "dap_list.h" +#include "dap_common.h" +#include "dap_strfuncs.h" +#include "utlist.h" +#include "dap_chain_plugins_manifest.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#undef LOG_TAG +#define LOG_TAG "dap_chain_plugins_list" + +typedef struct dap_chain_list_plugin_module{ + char *name; + PyObject *obj_module; + bool isFuncOnChainsUpdated; + bool isFuncOnGdbUpdated; + bool isFuncOnNetStatusChanged; + struct dap_chain_list_plugin_module *next; +}dap_chain_plugin_list_module_t; + +static dap_chain_plugin_list_module_t* m_dap_chain_plugins_module_list; + +void dap_chain_plugins_list_init(); + +dap_chain_plugin_list_module_t* dap_chain_plugins_list_get(); + +bool dap_chain_plugins_list_check_load_plugins(dap_chain_plugins_list_char_t *list); + +void dap_chain_plugins_list_add(PyObject *module, const char *name); + +#ifdef __cplusplus +extern "C" { +#endif +#endif // _DAP_CHAIN_PLUGINS_LIST_ diff --git a/include/dap_chain_plugins_manifest.h b/include/dap_chain_plugins_manifest.h new file mode 100644 index 0000000000000000000000000000000000000000..107a6c213b2ecc8f8af68f0491fde61fdbf1c657 --- /dev/null +++ b/include/dap_chain_plugins_manifest.h @@ -0,0 +1,47 @@ +#ifndef _DAP_CHAIN_PLUGINS_MANIFEST_ +#define _DAP_CHAIN_PLUGINS_MANIFEST_ +#include "dap_common.h" +#include "dap_strfuncs.h" +#include "stdio.h" +#include "json-c/json_object.h" +#include "json-c/json_tokener.h" +#include "utlist.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +#undef LOG_TAG +#define LOG_TAG "dap_chain_plugins_manifest" + +typedef struct dap_chain_plugins_list_char{ + char *value; + struct dap_chain_plugins_list_char *next; +}dap_chain_plugins_list_char_t; + +typedef struct dap_list_manifest{ + char *name; + char *version; + char *author; + char *description; + dap_chain_plugins_list_char_t *dependencys; + struct dap_list_manifest *next; +}dap_chain_plugins_list_manifest_t; + +dap_chain_plugins_list_manifest_t* manifests; + +dap_chain_plugins_list_manifest_t *dap_chain_plugins_manifest_new(const char *name, const char *version, const dap_chain_plugins_list_char_t *dep, const char *author, + const char *description); + +void dap_chain_plugins_manifest_list_create(); + +dap_chain_plugins_list_manifest_t* dap_chain_plugins_manifests_get_list(); + +dap_chain_plugins_list_manifest_t* dap_chain_plugins_add_manifest_from_file(const char *file_path); + +bool dap_chain_plugins_manifest_list_add_from_file(const char *path_file); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/dap_chain_plugins.c b/src/dap_chain_plugins.c new file mode 100644 index 0000000000000000000000000000000000000000..ff3654eb6369a5889c8c438314de67bb5bbe4c24 --- /dev/null +++ b/src/dap_chain_plugins.c @@ -0,0 +1,123 @@ +#include "dap_chain_plugins.h" + +int dap_chain_plugins_init(dap_config_t *config){ + if(dap_config_get_item_bool_default(config, "plugins", "py_load", false)){ + plugins_root_path = dap_config_get_item_str_default(config, "plugins", "py_path", + "/opt/cellframe-node/var/plugins/"); + log_it(L_INFO, "Start initialize python plugins. Path plugins %s", plugins_root_path); + if (!dap_dir_test(plugins_root_path)){ + log_it(L_ERROR, "The directory %s was not found.", plugins_root_path); + return -1; + } + Py_Initialize(); + PyObject *sys_module = PyImport_ImportModule("sys"); + sys_path = PyObject_GetAttrString(sys_module, "path"); + //Get list files + dap_list_name_directories_t *list_plugins_name = dap_get_subs(plugins_root_path); + dap_list_name_directories_t *element; + //Loading manifest and start module + log_it(L_NOTICE, "Registration manifests"); + dap_chain_plugins_manifest_list_create(); + dap_chain_plugins_list_init(); + char *name_file = NULL; + LL_FOREACH(list_plugins_name, element){ + log_it(L_NOTICE, "Registration %s manifest", element->name_directory); + name_file = dap_strjoin("",plugins_root_path, element->name_directory, "/manifest.json", NULL); + if (!dap_chain_plugins_manifest_list_add_from_file(name_file)){ + log_it(L_ERROR, "Registration %s manifest fail", element->name_directory); + } + DAP_FREE(name_file); + } + dap_chain_plugins_loading(); + }else{ + log_it(L_NOTICE, "Permission to initialize python plugins has not been obtained."); + return -2; + } + return 0; +} +void dap_chain_plugins_deinit(){ + Py_Finalize(); +} + +void dap_chain_plugins_loading(){ + log_it(L_NOTICE, "Loading plugins"); + dap_chain_plugins_list_manifest_t *l_manifests = dap_chain_plugins_manifests_get_list(); + dap_chain_plugins_list_manifest_t *man = NULL; + dap_chain_plugins_list_manifest_t *treshold = NULL; + dap_chain_plugins_list_manifest_t *tmp = NULL; + LL_FOREACH_SAFE(l_manifests, man, tmp){ + if (man->name == NULL){ + log_it(L_ERROR, "Can loading plugin, file not found"); + break; + } + log_it(L_NOTICE, "Check dependencys for plugin %s", man->name); + if (man->dependencys != NULL){ + log_it(L_NOTICE, "Plugin have dependencys"); + if (!dap_chain_plugins_list_check_load_plugins(man->dependencys)){ + log_it(L_NOTICE, "Plugin %s add treshold", man->name); + LL_APPEND(treshold, man); + }else{ + dap_chain_plugins_load_plugin(dap_strjoin("", plugins_root_path, man->name, "/", NULL), man->name); + } + }else{ + dap_chain_plugins_load_plugin(dap_strjoin("", plugins_root_path, man->name, "/", NULL), man->name); + } + } + + int c_processed = 0; + int step_processed = 0; + int len; + LL_COUNT(treshold, man, len); + do{ + LL_FOREACH_SAFE(treshold, man, tmp){ + if (dap_chain_plugins_list_check_load_plugins(man->dependencys)){ + log_it(L_NOTICE, "For plugin %s loading all dependecys", man->name); + dap_chain_plugins_load_plugin(dap_strjoin("", plugins_root_path, man->name, "/", NULL), man->name); + LL_DELETE(treshold, man); + c_processed++; + step_processed = 0; + } + } + step_processed++; + }while(c_processed < len && step_processed <= 2); + //Check loading all treshold + LL_COUNT(treshold, man, len); + if (len > 0){ + log_it(L_WARNING, "I can't loading some plugins from list treshold"); + LL_FOREACH(treshold, man){ + log_it(L_ERROR, "The plugin %s does not load with a dependency resolution error.", man->name); + } + } +} +void dap_chain_plugins_load_plugin(const char *dir_path, const char *name){ + log_it(L_NOTICE, "Loading %s plugin directory %s", name, dir_path); + PyErr_Clear(); + + PyObject *obj_dir_path = PyUnicode_FromString(dir_path); + PyList_Append(sys_path, obj_dir_path); + Py_XDECREF(obj_dir_path); + PyObject *module = PyImport_ImportModule(name); + PyObject *func_init = PyObject_GetAttrString(module, "init"); + PyObject *func_deinit = PyObject_GetAttrString(module, "deinit"); + PyObject *res_int = NULL; + PyErr_Clear(); + if (func_init != NULL && PyCallable_Check(func_init)){ + res_int = PyEval_CallObject(func_init, NULL); + if (res_int && PyLong_Check(res_int)){ + if (_PyLong_AsInt(res_int) == 0){ + dap_chain_plugins_list_add(module, name); + } else { + log_it(L_ERROR, "Code error %i at initialization %s plugin", _PyLong_AsInt(res_int), name); + } + } else { + log_it(L_ERROR, "Function initialization %s plugin don't reterned integer value", name); + } + Py_XDECREF(res_int); + }else { + log_it(L_ERROR, "For plugins %s don't found function init", name); + } + if (func_deinit == NULL || !PyCallable_Check(func_deinit)){ + log_it(L_WARNING, "For plugins %s don't found function deinit", name); + } +} + diff --git a/src/dap_chain_plugins_list.c b/src/dap_chain_plugins_list.c new file mode 100644 index 0000000000000000000000000000000000000000..9529b01aa35932c14f845fdf4372c6a1a11bcdc9 --- /dev/null +++ b/src/dap_chain_plugins_list.c @@ -0,0 +1,59 @@ +#include "dap_chain_plugins_list.h" + +void dap_chain_plugins_list_init(){ + m_dap_chain_plugins_module_list = NULL; +} + +void dap_chain_plugins_list_add(PyObject *module, const char *name){ + dap_chain_plugin_list_module_t *elemnet = (dap_chain_plugin_list_module_t*)DAP_NEW(dap_chain_plugin_list_module_t); + elemnet->name = dap_strdup(name); + elemnet->obj_module = module; + elemnet->isFuncOnGdbUpdated = true; + elemnet->isFuncOnChainsUpdated = true; + elemnet->isFuncOnNetStatusChanged = true; + //Checking function + PyObject *F_FuncOnGdbUpdated = PyObject_GetAttrString(elemnet->obj_module, "onGdbUpdated"); + PyObject *F_FuncOnChainsUpdated = PyObject_GetAttrString(elemnet->obj_module, "onChainsUpdated"); + PyObject *F_FuncOnNetStatusChanged = PyObject_GetAttrString(elemnet->obj_module, "onNetStatusChanged"); + if (F_FuncOnGdbUpdated == NULL || !PyCallable_Check(F_FuncOnGdbUpdated)){ + log_it(L_WARNING, "Plugin %s don't callable function onGdbUpdated", elemnet->name); + elemnet->isFuncOnGdbUpdated = false; + } + if (F_FuncOnChainsUpdated == NULL || !PyCallable_Check(F_FuncOnChainsUpdated)){ + log_it(L_WARNING, "Plugin %s don't callable function onChainsUpdated", elemnet->name); + elemnet->isFuncOnChainsUpdated = false; + } + if (F_FuncOnNetStatusChanged == NULL || !PyCallable_Check(F_FuncOnNetStatusChanged)){ + log_it(L_WARNING, "Plugin %s don't callable function onNetStatusChanged", elemnet->name); + elemnet->isFuncOnNetStatusChanged = false; + } + LL_APPEND(m_dap_chain_plugins_module_list, elemnet); +} + +dap_chain_plugin_list_module_t* dap_chain_plugins_list_get(){ + return m_dap_chain_plugins_module_list; +} + +int dap_chain_plugins_list_cmp(dap_chain_plugin_list_module_t *e1, dap_chain_plugin_list_module_t *e2){ + return strcmp(e1->name, e2->name); +} + +bool dap_chain_plugins_list_check_load_plugins(dap_chain_plugins_list_char_t *list){ + dap_chain_plugins_list_char_t *value_from_list = NULL; + dap_chain_plugin_list_module_t *element_from_list_module; + dap_chain_plugin_list_module_t *element_lnk = (dap_chain_plugin_list_module_t*)DAP_NEW( + dap_chain_plugin_list_module_t); + + int lenght; + LL_COUNT(m_dap_chain_plugins_module_list, element_from_list_module, lenght); + if (lenght == 0) + return false; + LL_FOREACH(list, value_from_list){ + element_lnk->name = value_from_list->value; + LL_SEARCH(m_dap_chain_plugins_module_list, element_from_list_module, element_lnk, dap_chain_plugins_list_cmp); + if (!element_from_list_module) + return false; + } + return true; +} + diff --git a/src/dap_chain_plugins_manifest.c b/src/dap_chain_plugins_manifest.c new file mode 100644 index 0000000000000000000000000000000000000000..4a202f98279d01c0b5e6206d72ed755e221c6754 --- /dev/null +++ b/src/dap_chain_plugins_manifest.c @@ -0,0 +1,84 @@ +#include "dap_chain_plugins_manifest.h" + +dap_chain_plugins_list_manifest_t *dap_chain_plugins_manifest_new(const char *name, const char *version, const dap_chain_plugins_list_char_t *dep, const char *author, + const char *description){ + dap_chain_plugins_list_manifest_t *man = (dap_chain_plugins_list_manifest_t*)DAP_NEW(dap_chain_plugins_list_manifest_t); + man->name = dap_strdup(name); + man->author = dap_strdup(author); + man->version = dap_strdup(version); + man->description = dap_strdup(description); + man->dependencys = NULL; + //copy informantion from dep to man->dependencys + int len_dep; + dap_chain_plugins_list_char_t *char_t; + LL_COUNT((dap_chain_plugins_list_char_t*)dep, char_t, len_dep); + LL_FOREACH((dap_chain_plugins_list_char_t*)dep, char_t){ + LL_APPEND(man->dependencys, char_t); + } + man->dependencys = (dap_chain_plugins_list_char_t*)dep; + return man; +} + +static dap_chain_plugins_list_char_t* JSON_array_to_dap_list_char(json_object *j_obj){ + dap_chain_plugins_list_char_t *list = NULL; + dap_chain_plugins_list_char_t *element = NULL; + for (int i = 0; i < json_object_array_length(j_obj); i++){ + element = (dap_chain_plugins_list_char_t*)DAP_NEW(dap_chain_plugins_list_char_t); + element->value = dap_strdup(json_object_get_string(json_object_array_get_idx(j_obj, i))); + LL_APPEND(list, element); + } + return list; +} + +void dap_chain_plugins_manifest_list_create(){ + manifests = NULL; +} + +dap_chain_plugins_list_manifest_t* dap_chain_plugins_add_manifest_from_file(const char *file_path){ + //READ File in char + log_it(L_INFO, "Parse json file"); + FILE *file = fopen(file_path, "rt"); + if (file == NULL){ + log_it(L_ERROR, "Error open manifest files along the way %s", file_path); + return NULL; + } + fseek(file, 0, SEEK_END); + size_t size_file = (size_t)ftell(file); + char *json = DAP_NEW_SIZE(char, size_file); + rewind(file); + fread(json, sizeof(char), size_file, file); + fclose(file); + //Parse JSON + json_object *j_obj = json_tokener_parse(json); + json_object *j_name = json_object_object_get(j_obj, "name"); + json_object *j_version = json_object_object_get(j_obj, "version"); + json_object *j_dependencys = json_object_object_get(j_obj, "dependencys"); + json_object *j_author = json_object_object_get(j_obj, "author"); + json_object *j_description = json_object_object_get(j_obj, "description"); + const char *name, *version, *author, *description; + name = json_object_get_string(j_name); + version = json_object_get_string(j_version); + author = json_object_get_string(j_author); + description = json_object_get_string(j_description); + dap_chain_plugins_list_char_t *dep = JSON_array_to_dap_list_char(j_dependencys); + DAP_FREE(json); + dap_chain_plugins_list_char_t *tmp = NULL; + dap_chain_plugins_list_manifest_t *manifest = dap_chain_plugins_manifest_new(name, version, dep, author, description); + return manifest; +} + +void dap_chain_plugins_manifest_list_add_manifest(dap_chain_plugins_list_manifest_t *man){ + LL_APPEND(manifests, man); +} + +dap_chain_plugins_list_manifest_t* dap_chain_plugins_manifests_get_list(){ + return manifests; +} + +bool dap_chain_plugins_manifest_list_add_from_file(const char *file_path){ + dap_chain_plugins_list_manifest_t *manifest = dap_chain_plugins_add_manifest_from_file(file_path); + if (manifest == NULL) + return false; + dap_chain_plugins_manifest_list_add_manifest(manifest); + return true; +}