blob: 94d4c446867cf8096c9cee531ccb3f952c3faa2c [file] [log] [blame]
Václav Kubernát73109382018-09-14 19:52:03 +02001/*
2 * Copyright (C) 2018 CESNET, https://photonics.cesnet.cz/
3 * Copyright (C) 2018 FIT CVUT, https://fit.cvut.cz/
4 *
5 * Written by Václav Kubernát <kubervac@fit.cvut.cz>
6 *
7*/
8
Václav Kubernát19097f32020-10-05 10:08:29 +02009#include <experimental/iterator>
10#include <sstream>
Václav Kubernát73109382018-09-14 19:52:03 +020011#include <sysrepo-cpp/Session.hpp>
12#include "sysrepo_subscription.hpp"
Václav Kubernát654303f2020-07-31 13:16:54 +020013#include "utils.hpp"
Václav Kubernát73109382018-09-14 19:52:03 +020014
15
Václav Kubernát654303f2020-07-31 13:16:54 +020016class MyCallback {
Václav Kubernát73109382018-09-14 19:52:03 +020017public:
18 MyCallback(const std::string& moduleName, Recorder* rec)
19 : m_moduleName(moduleName)
20 , m_recorder(rec)
21 {
22 }
23
Václav Kubernátcfdb9222021-07-07 22:36:24 +020024 sysrepo::ErrorCode operator()(
25 sysrepo::Session sess,
26 uint32_t /* sub_id */,
27 std::string_view module_name,
28 std::optional<std::string_view> /* sub_xpath */,
29 sysrepo::Event event,
30 uint32_t /* request_id */)
Václav Kubernát73109382018-09-14 19:52:03 +020031 {
32 using namespace std::string_literals;
Václav Kubernátcfdb9222021-07-07 22:36:24 +020033 if (event == sysrepo::Event::Change) {
34 return sysrepo::ErrorCode::Ok;
Václav Kubernát3a433232020-07-08 17:52:50 +020035 }
Václav Kubernát73109382018-09-14 19:52:03 +020036
Jan Kundrátf59b83c2022-03-18 18:12:08 +010037 for (const auto& it : sess.getChanges("/"s + module_name.data() + ":*//.")) {
Václav Kubernátcfdb9222021-07-07 22:36:24 +020038 auto xpath = it.node.path();
39 std::optional<std::string> oldValue;
40 std::optional<std::string> newValue;
41 if (it.operation == sysrepo::ChangeOperation::Deleted) {
42 oldValue = it.node.schema().nodeType() == libyang::NodeType::Leaf || it.node.schema().nodeType() == libyang::NodeType::Leaflist ?
43 std::optional<std::string>{it.node.asTerm().valueStr()} :
44 std::nullopt;
45 } else {
46 oldValue = std::optional<std::string>{it.previousValue};
47 newValue = it.node.schema().nodeType() == libyang::NodeType::Leaf || it.node.schema().nodeType() == libyang::NodeType::Leaflist ?
48 std::optional<std::string>{it.node.asTerm().valueStr()} :
49 std::nullopt;
Václav Kubernát654303f2020-07-31 13:16:54 +020050
Václav Kubernátcfdb9222021-07-07 22:36:24 +020051 }
52 std::optional<std::string> previousList;
Václav Kubernát69aabe92020-01-24 16:53:12 +010053
Václav Kubernátcfdb9222021-07-07 22:36:24 +020054 if (it.previousList) {
55 previousList = std::string{*it.previousList};
56 }
57
58 m_recorder->write(it.operation, std::string{xpath}, oldValue, newValue, previousList);
Václav Kubernát73109382018-09-14 19:52:03 +020059 }
60
Václav Kubernátcfdb9222021-07-07 22:36:24 +020061 return sysrepo::ErrorCode::Ok;
Václav Kubernát73109382018-09-14 19:52:03 +020062 }
63
64private:
65 std::string m_moduleName;
66 Recorder* m_recorder;
67};
68
69Recorder::~Recorder() = default;
70
Jan Kundrátbb525b42020-02-04 11:56:59 +010071DataSupplier::~DataSupplier() = default;
72
Václav Kubernátcfdb9222021-07-07 22:36:24 +020073SysrepoSubscription::SysrepoSubscription(const std::string& moduleName, Recorder* rec, sysrepo::Datastore ds)
74 : m_subscription([&moduleName, &rec, ds] { // This is an immediately invoked lambda.
Jan Kundrátf59b83c2022-03-18 18:12:08 +010075 return sysrepo::Connection{}.sessionStart(ds).onModuleChange(moduleName,
Václav Kubernátcfdb9222021-07-07 22:36:24 +020076 rec ? sysrepo::ModuleChangeCb{MyCallback{moduleName, rec}}
77 : sysrepo::ModuleChangeCb{[](auto, auto, auto, auto, auto, auto) { return sysrepo::ErrorCode::Ok; }});
78 }())
Václav Kubernát73109382018-09-14 19:52:03 +020079{
Václav Kubernát73109382018-09-14 19:52:03 +020080}
Jan Kundrátbb525b42020-02-04 11:56:59 +010081
Václav Kubernát654303f2020-07-31 13:16:54 +020082class OperationalDataCallback {
Jan Kundrátbb525b42020-02-04 11:56:59 +010083public:
84 OperationalDataCallback(const DataSupplier& dataSupplier)
85 : m_dataSupplier(dataSupplier)
86 {
87 }
Václav Kubernátcfdb9222021-07-07 22:36:24 +020088 sysrepo::ErrorCode operator()(
89 sysrepo::Session session,
90 [[maybe_unused]] uint32_t subscriptionId,
91 [[maybe_unused]] std::string_view moduleName,
92 std::optional<std::string_view> subXPath,
93 [[maybe_unused]] std::optional<std::string_view> requestXPath,
94 [[maybe_unused]] uint32_t requestId,
95 std::optional<libyang::DataNode>& output)
Jan Kundrátbb525b42020-02-04 11:56:59 +010096 {
Václav Kubernátcfdb9222021-07-07 22:36:24 +020097 auto data = m_dataSupplier.get_data(subXPath->data());
Václav Kubernát654303f2020-07-31 13:16:54 +020098 for (const auto& [p, v] : data) {
Václav Kubernátcfdb9222021-07-07 22:36:24 +020099 if (!output) {
Jan Kundrátf59b83c2022-03-18 18:12:08 +0100100 output = session.getContext().newPath(p, v.type() == typeid(empty_) ? std::nullopt : std::optional<std::string>(leafDataToString(v)));
Václav Kubernát654303f2020-07-31 13:16:54 +0200101 } else {
Jan Kundrátf59b83c2022-03-18 18:12:08 +0100102 output->newPath(p, v.type() == typeid(empty_) ? std::nullopt : std::optional<std::string>(leafDataToString(v)));
Václav Kubernát654303f2020-07-31 13:16:54 +0200103 }
Jan Kundrátbb525b42020-02-04 11:56:59 +0100104 }
Václav Kubernátcfdb9222021-07-07 22:36:24 +0200105 return sysrepo::ErrorCode::Ok;
Jan Kundrátbb525b42020-02-04 11:56:59 +0100106 }
Václav Kubernátb4e5b182020-11-16 19:55:09 +0100107
Jan Kundrátbb525b42020-02-04 11:56:59 +0100108private:
109 const DataSupplier& m_dataSupplier;
110};
111
Václav Kubernát654303f2020-07-31 13:16:54 +0200112OperationalDataSubscription::OperationalDataSubscription(const std::string& moduleName, const std::string& path, const DataSupplier& dataSupplier)
Jan Kundrátf59b83c2022-03-18 18:12:08 +0100113 : m_subscription(sysrepo::Connection{}.sessionStart().onOperGet(moduleName, OperationalDataCallback{dataSupplier}, path))
Jan Kundrátbb525b42020-02-04 11:56:59 +0100114{
Jan Kundrátbb525b42020-02-04 11:56:59 +0100115}