From: Vasek Sraier Date: Sun, 26 Jan 2020 14:48:08 +0000 (+0100) Subject: sysrepo-lua: migrated module code from sysrepo-module-lua branch X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=26c746a55f29e95eb2abf82ac09dc19f6ee7f342;p=thirdparty%2Fknot-resolver.git sysrepo-lua: migrated module code from sysrepo-module-lua branch Because this is not a merge commit, line history was lost. But it does not matter that much, because pretty much all the commited code was written by me and it's mainly a proof of concept. Nothing important should have been lost. --- diff --git a/meson.build b/meson.build index 948880ee1..a3c2f6950 100644 --- a/meson.build +++ b/meson.build @@ -114,7 +114,7 @@ message('---------------------------') ### Sysrepo message('--- sysrepo dependencies ---') -libsysrepo = dependency('sysrepo', version: '>=1', required: false) +libsysrepo = dependency('libsysrepo', version: '>=1', required: false) libyang = dependency('libyang', version: '>=1', required: false) sysrepo = get_option('sysrepo') if (sysrepo == 'auto' or sysrepo == 'enabled') and libsysrepo.found() and libyang.found() diff --git a/modules/sysrepo-lua/cbindings/sysrepo_clib.c b/modules/sysrepo-lua/cbindings/sysrepo_clib.c new file mode 100644 index 000000000..222013098 --- /dev/null +++ b/modules/sysrepo-lua/cbindings/sysrepo_clib.c @@ -0,0 +1,205 @@ +/* Copyright (C) 2020 CZ.NIC, z.s.p.o. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#include "sysrepo_clib.h" + +#include +#include +#include +#include + +#include "lib/module.h" +#include "common/sysrepo_conf.h" + +EXPORT_STRDEF_TO_LUA_IMPL(YM_COMMON) +EXPORT_STRDEF_TO_LUA_IMPL(XPATH_BASE) + +struct el_subscription_ctx { + sr_conn_ctx_t *connection; + sr_session_ctx_t *session; + sr_subscription_ctx_t *subscription; + el_subsription_cb callback; + uv_poll_t uv_handle; +}; + +/** Callback to Lua used for applying configuration */ +static set_leaf_conf_t apply_conf_f = NULL; +static el_subscription_ctx_t *el_subscription_ctx = NULL; + +/** + * Change callback getting called by sysrepo. Iterates over changed options and passes + * them over to Lua. + */ +static int sysrepo_conf_change_callback(sr_session_ctx_t *session, + const char *module_name, + const char *xpath, sr_event_t event, + uint32_t request_id, void *private_data) +{ + if (event == SR_EV_CHANGE) { + // gets called before the actual change of configuration is commited. If we + // return an error, the change is aborted can be used for configuration + // verification. Must have no sideeffects. + + // TODO + } else if (event == SR_EV_ABORT) { + // Gets called when the transaction gets aborted. Because we have no + // sideeffects during verification, we don't care and and there is nothing + // to do + } else if (event == SR_EV_DONE) { + // after configuration change commit. We should apply the configuration. + // Will not hurt if we verify the changes again, but we have no way of + // declining the change now + + int sr_err = SR_ERR_OK; + sr_change_iter_t *it = NULL; + sr_change_oper_t oper; + sr_val_t *old_value = NULL; + sr_val_t *new_value = NULL; + + // get all changes + sr_err = sr_get_changes_iter(session, XPATH_BASE "//.", &it); + if (sr_err != SR_ERR_OK) + goto cleanup; + + while ((sr_get_change_next(session, it, &oper, &old_value, + &new_value)) == SR_ERR_OK) { + apply_conf_f(new_value); + } + cleanup: + if (sr_err != SR_ERR_OK && sr_err != SR_ERR_NOT_FOUND) + kr_log_error("Sysrepo module error: %s\n", + sr_strerror(sr_err)); + sr_free_val(old_value); + sr_free_val(new_value); + sr_free_change_iter(it); + } + return SR_ERR_OK; +} + +void el_subscr_finish_closing(uv_handle_t *handle) +{ + el_subscription_ctx_t *el_subscr = handle->data; + assert(el_subscr != NULL); + free(el_subscr); +} + +/** Free a event loop subscription. */ +void el_subscription_free(el_subscription_ctx_t *el_subscr) +{ + sr_disconnect(el_subscr->connection); + uv_close((uv_handle_t *)&el_subscr->uv_handle, + el_subscr_finish_closing); +} + +static void el_subscr_cb_tramp(uv_poll_t *handle, int status, int events) +{ + el_subscription_ctx_t *el_subscr = handle->data; + el_subscr->callback(el_subscr, status); +} + +/** Start a new event loop subscription. */ +static el_subscription_ctx_t * +el_subscription_new(sr_subscription_ctx_t *sr_subscr, + el_subsription_cb el_callback) +{ + int fd; + int err = sr_get_event_pipe(sr_subscr, &fd); + if (err != SR_ERR_OK) + return NULL; + el_subscription_ctx_t *el_subscr = malloc(sizeof(*el_subscr)); + if (el_subscr == NULL) + return NULL; + err = uv_poll_init(uv_default_loop(), &el_subscr->uv_handle, fd); + if (err != 0) { + free(el_subscr); + return NULL; + } + el_subscr->subscription = sr_subscr; + el_subscr->callback = el_callback; + el_subscr->uv_handle.data = el_subscr; + err = uv_poll_start(&el_subscr->uv_handle, UV_READABLE, + el_subscr_cb_tramp); + if (err != 0) { + el_subscription_free(el_subscr); + return NULL; + } + return el_subscr; +} + +static void el_subscr_cb(el_subscription_ctx_t *el_subscr, int status) +{ + if (status) { + /* some error */ + return; + } + /* normal state */ + sr_process_events(el_subscr->subscription, el_subscr->session, NULL); +} + +int sysrepo_init(set_leaf_conf_t apply_conf_callback) +{ + // store callback to Lua + apply_conf_f = apply_conf_callback; + + int sr_err = SR_ERR_OK; + sr_conn_ctx_t *sr_connection = NULL; + sr_session_ctx_t *sr_session = NULL; + sr_subscription_ctx_t *sr_subscription = NULL; + + sr_err = sr_connect(0, &sr_connection); + if (sr_err != SR_ERR_OK) + goto cleanup; + + sr_err = sr_connection_recover(sr_connection); + if (sr_err != SR_ERR_OK) + goto cleanup; + + sr_err = sr_session_start(sr_connection, SR_DS_RUNNING, &sr_session); + if (sr_err != SR_ERR_OK) + goto cleanup; + + /* register sysrepo subscriptions and callbacks + SR_SUBSCR_NO_THREAD - don't create a thread for handling them + SR_SUBSCR_ENABLED - send us current configuration in a callback just after subscribing + */ + sr_err = sr_module_change_subscribe( + sr_session, YM_COMMON, XPATH_BASE, sysrepo_conf_change_callback, + NULL, 0, SR_SUBSCR_NO_THREAD | SR_SUBSCR_ENABLED, + &sr_subscription); + if (sr_err != SR_ERR_OK) + goto cleanup; + + /* add subscriptions to kres event loop */ + el_subscription_ctx = + el_subscription_new(sr_subscription, el_subscr_cb); + el_subscription_ctx->connection = sr_connection; + el_subscription_ctx->session = sr_session; + + return kr_ok(); + +cleanup: + sr_disconnect(sr_connection); + kr_log_error("Error (%s)\n", sr_strerror(sr_err)); + return kr_error(sr_err); +} + +int sysrepo_deinit() +{ + el_subscription_free(el_subscription_ctx); + // remove reference to Lua callback so that it can be free'd safely + apply_conf_f = NULL; + return kr_ok(); +} diff --git a/modules/sysrepo-lua/cbindings/sysrepo_clib.h b/modules/sysrepo-lua/cbindings/sysrepo_clib.h new file mode 100644 index 000000000..9ac10824a --- /dev/null +++ b/modules/sysrepo-lua/cbindings/sysrepo_clib.h @@ -0,0 +1,49 @@ +/* Copyright (C) 2020 CZ.NIC, z.s.p.o. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#pragma once + +/** + * This header file defines an interface between sysrepo_clib and the rest + * of the sysrepo module written in Lua. Functions and structs defined here + * might be used through LuaJIT's FFI. + */ + +#include "lib/defines.h" +#include "lib/utils.h" + +#include "common/sysrepo_conf.h" + +/** Generates prototype for functions exporting string constants from C to Lua */ +#define EXPORT_STRDEF_TO_LUA(name) char *get_strdef_##name(void); +/** Generates function to be used from within Lua to get access to string constants. */ +#define EXPORT_STRDEF_TO_LUA_IMPL(name) \ + char *get_strdef_##name() \ + { \ + return name; \ + } + +EXPORT_STRDEF_TO_LUA(YM_COMMON) +EXPORT_STRDEF_TO_LUA(XPATH_BASE) + +typedef struct el_subscription_ctx el_subscription_ctx_t; +/** Callback for our sysrepo subscriptions */ +typedef void (*el_subsription_cb)(el_subscription_ctx_t *el_subscr, int status); +/** Callback to Lua for applying configuration */ +typedef void (*set_leaf_conf_t)(sr_val_t *val); + +KR_EXPORT int sysrepo_init(set_leaf_conf_t set_leaf_conf_cb); +KR_EXPORT int sysrepo_deinit(void); diff --git a/modules/sysrepo-lua/common b/modules/sysrepo-lua/common new file mode 120000 index 000000000..2fd86f2cf --- /dev/null +++ b/modules/sysrepo-lua/common @@ -0,0 +1 @@ +../sysrepo/common \ No newline at end of file diff --git a/modules/sysrepo-lua/ffi.lua b/modules/sysrepo-lua/ffi.lua new file mode 100644 index 000000000..355dcb149 --- /dev/null +++ b/modules/sysrepo-lua/ffi.lua @@ -0,0 +1,246 @@ +local ffi = require("ffi") + +-- FIXME remove absolute path +-- the load opens the file relative to CWD. That could be anywhere. So we need to know, where is knot installed. +local clib = ffi.load("/tmp/kr/lib/knot-resolver/kres_modules/sysrepo-lua/cbindings.so") + +------------------------------------------------------------------------------- +-- FFI initialization +------------------------------------------------------------------------------- + +local function initialize_ffi() + --- Definition of `sr_val_t` copied from sysrepo.h on 2020-01-01. + ffi.cdef[[ + /** + * @brief Possible types of a data element stored in the sysrepo datastore. + */ + typedef enum sr_type_e { + /* special types that does not contain any data */ + SR_UNKNOWN_T, /**< Element unknown to sysrepo (unsupported element). */ + + SR_LIST_T, /**< List instance. ([RFC 7950 sec 7.8](http://tools.ietf.org/html/rfc7950#section-7.8)) */ + SR_CONTAINER_T, /**< Non-presence container. ([RFC 7950 sec 7.5](http://tools.ietf.org/html/rfc7950#section-7.5)) */ + SR_CONTAINER_PRESENCE_T, /**< Presence container. ([RFC 7950 sec 7.5.1](http://tools.ietf.org/html/rfc7950#section-7.5.1)) */ + SR_LEAF_EMPTY_T, /**< A leaf that does not hold any value ([RFC 7950 sec 9.11](http://tools.ietf.org/html/rfc7950#section-9.11)) */ + SR_NOTIFICATION_T, /**< Notification instance ([RFC 7095 sec 7.16](https://tools.ietf.org/html/rfc7950#section-7.16)) */ + + /* types containing some data */ + SR_BINARY_T, /**< Base64-encoded binary data ([RFC 7950 sec 9.8](http://tools.ietf.org/html/rfc7950#section-9.8)) */ + SR_BITS_T, /**< A set of bits or flags ([RFC 7950 sec 9.7](http://tools.ietf.org/html/rfc7950#section-9.7)) */ + SR_BOOL_T, /**< A boolean value ([RFC 7950 sec 9.5](http://tools.ietf.org/html/rfc7950#section-9.5)) */ + SR_DECIMAL64_T, /**< 64-bit signed decimal number ([RFC 7950 sec 9.3](http://tools.ietf.org/html/rfc7950#section-9.3)) */ + SR_ENUM_T, /**< A string from enumerated strings list ([RFC 7950 sec 9.6](http://tools.ietf.org/html/rfc7950#section-9.6)) */ + SR_IDENTITYREF_T, /**< A reference to an abstract identity ([RFC 7950 sec 9.10](http://tools.ietf.org/html/rfc7950#section-9.10)) */ + SR_INSTANCEID_T, /**< References a data tree node ([RFC 7950 sec 9.13](http://tools.ietf.org/html/rfc7950#section-9.13)) */ + SR_INT8_T, /**< 8-bit signed integer ([RFC 7950 sec 9.2](https://tools.ietf.org/html/rfc7950#section-9.2)) */ + SR_INT16_T, /**< 16-bit signed integer ([RFC 7950 sec 9.2](https://tools.ietf.org/html/rfc7950#section-9.2)) */ + SR_INT32_T, /**< 32-bit signed integer ([RFC 7950 sec 9.2](https://tools.ietf.org/html/rfc7950#section-9.2)) */ + SR_INT64_T, /**< 64-bit signed integer ([RFC 7950 sec 9.2](https://tools.ietf.org/html/rfc7950#section-9.2)) */ + SR_STRING_T, /**< Human-readable string ([RFC 7950 sec 9.4](http://tools.ietf.org/html/rfc7950#section-9.4)) */ + SR_UINT8_T, /**< 8-bit unsigned integer ([RFC 7950 sec 9.2](https://tools.ietf.org/html/rfc7950#section-9.2)) */ + SR_UINT16_T, /**< 16-bit unsigned integer ([RFC 7950 sec 9.2](https://tools.ietf.org/html/rfc7950#section-9.2)) */ + SR_UINT32_T, /**< 32-bit unsigned integer ([RFC 7950 sec 9.2](https://tools.ietf.org/html/rfc7950#section-9.2)) */ + SR_UINT64_T, /**< 64-bit unsigned integer ([RFC 7950 sec 9.2](https://tools.ietf.org/html/rfc7950#section-9.2)) */ + SR_ANYXML_T, /**< Unknown chunk of XML ([RFC 7950 sec 7.10](https://tools.ietf.org/html/rfc7950#section-7.10)) */ + SR_ANYDATA_T, /**< Unknown set of nodes, encoded in XML ([RFC 7950 sec 7.10](https://tools.ietf.org/html/rfc7950#section-7.10)) */ + } sr_type_t; + + /** + * @brief Data of an element (if applicable), properly set according to the type. + */ + typedef union sr_data_u { + char *binary_val; /**< Base64-encoded binary data ([RFC 7950 sec 9.8](http://tools.ietf.org/html/rfc7950#section-9.8)) */ + char *bits_val; /**< A set of bits or flags ([RFC 7950 sec 9.7](http://tools.ietf.org/html/rfc7950#section-9.7)) */ + bool bool_val; /**< A boolean value ([RFC 7950 sec 9.5](http://tools.ietf.org/html/rfc7950#section-9.5)) */ + double decimal64_val; /**< 64-bit signed decimal number ([RFC 7950 sec 9.3](http://tools.ietf.org/html/rfc7950#section-9.3)) */ + char *enum_val; /**< A string from enumerated strings list ([RFC 7950 sec 9.6](http://tools.ietf.org/html/rfc7950#section-9.6)) */ + char *identityref_val; /**< A reference to an abstract identity ([RFC 7950 sec 9.10](http://tools.ietf.org/html/rfc7950#section-9.10)) */ + char *instanceid_val; /**< References a data tree node ([RFC 7950 sec 9.13](http://tools.ietf.org/html/rfc7950#section-9.13)) */ + int8_t int8_val; /**< 8-bit signed integer ([RFC 7950 sec 9.2](https://tools.ietf.org/html/rfc7950#section-9.2)) */ + int16_t int16_val; /**< 16-bit signed integer ([RFC 7950 sec 9.2](https://tools.ietf.org/html/rfc7950#section-9.2)) */ + int32_t int32_val; /**< 32-bit signed integer ([RFC 7950 sec 9.2](https://tools.ietf.org/html/rfc7950#section-9.2)) */ + int64_t int64_val; /**< 64-bit signed integer ([RFC 7950 sec 9.2](https://tools.ietf.org/html/rfc7950#section-9.2)) */ + char *string_val; /**< Human-readable string ([RFC 7950 sec 9.4](http://tools.ietf.org/html/rfc7950#section-9.4)) */ + uint8_t uint8_val; /**< 8-bit unsigned integer ([RFC 7950 sec 9.2](https://tools.ietf.org/html/rfc7950#section-9.2)) */ + uint16_t uint16_val; /**< 16-bit unsigned integer ([RFC 7950 sec 9.2](https://tools.ietf.org/html/rfc7950#section-9.2)) */ + uint32_t uint32_val; /**< 32-bit unsigned integer ([RFC 7950 sec 9.2](https://tools.ietf.org/html/rfc7950#section-9.2)) */ + uint64_t uint64_val; /**< 64-bit unsigned integer ([RFC 7950 sec 9.2](https://tools.ietf.org/html/rfc7950#section-9.2)) */ + char *anyxml_val; /**< Unknown chunk of XML ([RFC 7950 sec 7.10](https://tools.ietf.org/html/rfc7950#section-7.10)) */ + char *anydata_val; /**< Unknown set of nodes, encoded in XML ([RFC 7950 sec 7.10](https://tools.ietf.org/html/rfc7950#section-7.10)) */ + } sr_data_t; + + /** + * @brief Structure that contains value of an data element stored in the sysrepo datastore. + */ + typedef struct sr_val_s { + /** [XPath](@ref paths) (or rather path) identifier of the data element. */ + char *xpath; + + /** Type of an element. */ + sr_type_t type; + + /** + * Flag for node with default value (applicable only for leaves). + * It is set to TRUE only if the value was *implicitly* set by the datastore as per + * module schema. Explicitly set/modified data element (through the sysrepo API) always + * has this flag unset regardless of the entered value. + */ + bool dflt; + + /** [Origin](@ref oper_ds) of the value. */ + char *origin; + + /** Data of an element (if applicable), properly set according to the type. */ + sr_data_t data; + + } sr_val_t; + + typedef void (*set_leaf_conf_t)(sr_val_t *val); + int sysrepo_init(set_leaf_conf_t set_leaf_conf_cb); + int sysrepo_deinit(void); + ]] +end + +-- make sure this module runs just once +-- LuaJIT's FFI can't be initialized multiple times for the same types +if (_KNOT_SYSREPO_FFI_INITIALIZED == true) then + -- nothing to initialize then +else + initialize_ffi() + _KNOT_SYSREPO_FFI_INITIALIZED = true +end + +-- TODO version check so that we cant load new module into an old Knot + +------------------------------------------------------------------------------- +-- Data convertsion helpers +------------------------------------------------------------------------------- + +--- Helper table for converting sr_data_t union type to string based on the provided type +local _value_to_str_conversion_table = { + ["SR_UNKNOWN_T"] = function(_) return "unknown value" end, + ["SR_LIST_T"] = function(_) return "no value (list)" end, + ["SR_CONTAINER_T"] = function(_) return "no value (container)" end, + ["SR_CONTAINER_PRESENCE_T"] = function(_) return "container (container presence)" end, + ["SR_LEAF_EMPTY_T"] = function(_) return "empty (empty leaf)" end, + ["SR_NOTIFICATION_T"] = function(_) return "no value (notification)" end, + ["SR_BINARY_T"] = function(val) return ffi.string(val.binary_val) .. " (binary)" end, + ["SR_BITS_T"] = function(_) return "??? (bits)" end, + ["SR_BOOL_T"] = function(val) return tostring(val.bool_val) .. " (bool)" end, + ["SR_DECIMAL64_T"] = function(val) return tostring(val.decimal64_val) .. "(decimal64)" end, + ["SR_ENUM_T"] = function(val) return ffi.string(val.enum_val) .. " (enum)" end, + ["SR_IDENTITYREF_T"] = function(val) return ffi.string(val.enum_val) .. " (indentityref)" end, + ["SR_INSTANCEID_T"] = function(val) return ffi.string(val.enum_val) .. " (instanceid)" end, + ["SR_INT8_T"] = function(val) return tostring(val.int8_val) .. " (int8)" end, + ["SR_INT16_T"] = function(val) return tostring(val.int16_val) .. " (int16)" end, + ["SR_INT32_T"] = function(val) return tostring(val.int32_val) .. " (int32)" end, + ["SR_INT64_T"] = function(val) return tostring(val.int64_val) .. " (int64)" end, + ["SR_STRING_T"] = function(val) return ffi.string(val.string_val) .. " (string)" end, + ["SR_UINT8_T"] = function(val) return tostring(val.uint8_val) .. " (int8)" end, + ["SR_UINT16_T"] = function(val) return tostring(val.uint16_val) .. " (uint16)" end, + ["SR_UINT32_T"] = function(val) return tostring(val.uint32_val) .. " (uint32)" end, + ["SR_UINT64_T"] = function(val) return tostring(val.uint64_val) .. " (uint64)" end, + ["SR_ANYXML_T"] = function(val) return ffi.string(val.anyxml_val) .. " (anyxml)" end, + ["SR_ANYDATA_T"] = function(val) return ffi.string(val.anydata_val) .. " (anydata)" end, +} + +--- Convert from type sr_type_t into a uppercase string. +-- @param sr_type_t value. In case of wrong type, the function crashes the whole runtime. +-- @return string value of the enum +local function type_to_str(tp) + if (tp == "SR_UNKNOWN_T") then return "SR_UNKNOWN_T" + elseif (tp == "SR_LIST_T") then return "SR_LIST_T" + elseif (tp == "SR_CONTAINER_T") then return "SR_CONTAINER_T" + elseif (tp == "SR_CONTAINER_PRESENCE_T") then return "SR_CONTAINER_PRESENCE_T" + elseif (tp == "SR_LEAF_EMPTY_T") then return "SR_LEAF_EMPTY_T" + elseif (tp == "SR_NOTIFICATION_T") then return "SR_NOTIFICATION_T" + elseif (tp == "SR_BINARY_T") then return "SR_BINARY_T" + elseif (tp == "SR_BITS_T") then return "SR_BITS_T" + elseif (tp == "SR_BOOL_T") then return "SR_BOOL_T" + elseif (tp == "SR_DECIMAL64_T") then return "SR_DECIMAL64_T" + elseif (tp == "SR_ENUM_T") then return "SR_ENUM_T" + elseif (tp == "SR_IDENTITYREF_T") then return "SR_IDENTITYREF_T" + elseif (tp == "SR_INSTANCEID_T") then return "SR_INSTANCEID_T" + elseif (tp == "SR_INT8_T") then return "SR_INT8_T" + elseif (tp == "SR_INT16_T") then return "SR_INT16_T" + elseif (tp == "SR_INT32_T") then return "SR_INT32_T" + elseif (tp == "SR_INT64_T") then return "SR_INT64_T" + elseif (tp == "SR_STRING_T") then return "SR_STRING_T" + elseif (tp == "SR_UINT8_T") then return "SR_UINT8_T" + elseif (tp == "SR_UINT16_T") then return "SR_UINT16_T" + elseif (tp == "SR_UINT32_T") then return "SR_UINT32_T" + elseif (tp == "SR_UINT64_T") then return "SR_UINT64_T" + elseif (tp == "SR_ANYXML_T") then return "SR_ANYXML_T" + elseif (tp == "SR_ANYDATA_T") then return "SR_ANYDATA_T" + else + error("unexpected value of sr_type_t enum") + end +end + + +------------------------------------------------------------------------------- +-- Callback management +------------------------------------------------------------------------------- + +local callbacks = {} +local function create_callback(ctype ,func) + assert(type(ctype) == "string") + assert(type(func) == "function") + + local cb = ffi.cast(ctype, func) + table.insert(callbacks, cb) + return cb +end + +local function free_callbacks() + for _, cb in ipairs(callbacks) do + cb:free() + end +end + + +------------------------------------------------------------------------------- +-- Exported functionality +------------------------------------------------------------------------------- + +local sysrepo_ffi = {} + +function sysrepo_ffi.init(apply_conf_func) + local cb = create_callback("set_leaf_conf_t", apply_conf_func) + local res = clib.sysrepo_init(cb) + if res ~= 0 then + error("Initialization failed with error code " .. tostring(res)) + end +end + +function sysrepo_ffi.deinit() + local res = clib.sysrepo_deinit() + free_callbacks() + if res ~= 0 then + error("Deinitialization failed with error code " .. tostring(res)) + end +end + +--- Converts from cdata sr_val_t to table (using table is slower, but safer) +function sysrepo_ffi.sr_val_to_table(val) + local tbl = { + dflt = val.dflt, + xpath = ffi.string(val.xpath), + type = type_to_str(val.type), + _value = val.data, + } + setmetatable(tbl, { + __tostring = function(slf) + return string.format( + "{\n\txpath = '%s',\n\ttype = '%s',\n\tdflt = '%s',\n\tdata = '%s'\n}", + slf.xpath, + slf.type, + tostring(slf.dflt), + _value_to_str_conversion_table[type_to_str(slf.type)](slf._value) + ) + end + }) + return tbl +end + +return sysrepo_ffi diff --git a/modules/sysrepo-lua/init.lua b/modules/sysrepo-lua/init.lua new file mode 100644 index 000000000..8ba7daea2 --- /dev/null +++ b/modules/sysrepo-lua/init.lua @@ -0,0 +1,20 @@ +local sysrepo_ffi = require("kres_modules/sysrepo-lua/ffi") + +local sysrepo = {} + +local function apply_configuration(sr_val) + local sr_val_table = sysrepo_ffi.sr_val_to_table(sr_val) + + print("Configuration change") + print(tostring(sr_val_table)) +end + +function sysrepo.init() + sysrepo_ffi.init(apply_configuration) +end + +function sysrepo.deinit() + sysrepo_ffi.deinit() +end + +return sysrepo diff --git a/modules/sysrepo-lua/meson.build b/modules/sysrepo-lua/meson.build index bbe88c483..e8ad92316 100644 --- a/modules/sysrepo-lua/meson.build +++ b/modules/sysrepo-lua/meson.build @@ -1,8 +1,43 @@ # lua module: sysrepo-lua sysrepo_lua_src = files([ + 'ffi.lua', + 'init.lua', ]) +sysrepo_src = files([ + 'cbindings/sysrepo_clib.h', + 'cbindings/sysrepo_clib.c', +]) +c_src_lint += sysrepo_src + +sysrepo_common_src = files([ + 'common/sysrepo_conf.c', + 'common/sysrepo_conf.h', + 'common/string_helper.h', + 'common/string_helper.c', +]) +c_src_lint += sysrepo_common_src + if build_sysrepo + install_data( + sysrepo_lua_src, + install_dir: modules_dir + '/sysrepo-lua', + ) + sysrepo_mod = shared_module( + 'cbindings', + sysrepo_src, + dependencies: [ + luajit_inc, + libyang, + libsysrepo, + ], + include_directories: mod_inc_dir, + name_prefix: '', + install: true, + install_dir: modules_dir + '/sysrepo-lua', + ) endif + +