blob: 8faffa5aefef153aef458de7b78c3e52b90f7d77 [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át654303f2020-07-31 13:16:54 +020024 int operator()(
Václav Kubernátb4e5b182020-11-16 19:55:09 +010025 sysrepo::S_Session sess,
26 [[maybe_unused]] const char* module_name,
27 [[maybe_unused]] const char* xpath,
28 [[maybe_unused]] sr_event_t event,
29 [[maybe_unused]] uint32_t request_id)
Václav Kubernát73109382018-09-14 19:52:03 +020030 {
31 using namespace std::string_literals;
Václav Kubernát654303f2020-07-31 13:16:54 +020032 if (event == SR_EV_CHANGE) {
Václav Kubernát73109382018-09-14 19:52:03 +020033 return SR_ERR_OK;
Václav Kubernát3a433232020-07-08 17:52:50 +020034 }
Václav Kubernát73109382018-09-14 19:52:03 +020035
Václav Kubernát654303f2020-07-31 13:16:54 +020036 auto it = sess->get_changes_iter(("/"s + module_name + ":*//.").c_str());
37
Václav Kubernát73109382018-09-14 19:52:03 +020038 while (auto change = sess->get_change_next(it)) {
Václav Kubernát69aabe92020-01-24 16:53:12 +010039 auto xpath = (change->new_val() ? change->new_val() : change->old_val())->xpath();
40
41 auto oldValue = change->old_val() ? std::optional{change->old_val()->val_to_string()} : std::nullopt;
42 auto newValue = change->new_val() ? std::optional{change->new_val()->val_to_string()} : std::nullopt;
43 m_recorder->write(xpath, oldValue, newValue);
Václav Kubernát73109382018-09-14 19:52:03 +020044 }
45
46 return SR_ERR_OK;
47 }
48
49private:
50 std::string m_moduleName;
51 Recorder* m_recorder;
52};
53
54Recorder::~Recorder() = default;
55
Jan Kundrátbb525b42020-02-04 11:56:59 +010056DataSupplier::~DataSupplier() = default;
57
Václav Kubernáteaf56682021-02-22 17:15:41 +010058SysrepoSubscription::SysrepoSubscription(const std::string& moduleName, Recorder* rec, sr_datastore_t ds)
Václav Kubernát654303f2020-07-31 13:16:54 +020059 : m_connection(std::make_shared<sysrepo::Connection>())
Václav Kubernát73109382018-09-14 19:52:03 +020060{
Václav Kubernáteaf56682021-02-22 17:15:41 +010061 m_session = std::make_shared<sysrepo::Session>(m_connection, ds);
Václav Kubernát73109382018-09-14 19:52:03 +020062 m_subscription = std::make_shared<sysrepo::Subscribe>(m_session);
Václav Kubernát654303f2020-07-31 13:16:54 +020063 sysrepo::ModuleChangeCb cb;
Václav Kubernátab612e92019-11-26 19:51:31 +010064 if (rec) {
Václav Kubernát654303f2020-07-31 13:16:54 +020065 cb = MyCallback{moduleName, rec};
Václav Kubernátab612e92019-11-26 19:51:31 +010066 } else {
Václav Kubernátb4e5b182020-11-16 19:55:09 +010067 cb = [](auto, auto, auto, auto, auto) { return SR_ERR_OK; };
Václav Kubernátab612e92019-11-26 19:51:31 +010068 }
Václav Kubernát73109382018-09-14 19:52:03 +020069
Václav Kubernát654303f2020-07-31 13:16:54 +020070 m_subscription->module_change_subscribe(moduleName.c_str(), cb);
Václav Kubernát73109382018-09-14 19:52:03 +020071}
Jan Kundrátbb525b42020-02-04 11:56:59 +010072
Václav Kubernát654303f2020-07-31 13:16:54 +020073
Jan Kundrátbb525b42020-02-04 11:56:59 +010074struct leafDataToSysrepoVal {
Václav Kubernátb4e5b182020-11-16 19:55:09 +010075 leafDataToSysrepoVal(sysrepo::S_Val v, const std::string& xpath)
Jan Kundrátbb525b42020-02-04 11:56:59 +010076 : v(v)
77 , xpath(xpath)
78 {
79 }
80
81 void operator()(const binary_& what)
82 {
83 v->set(xpath.c_str(), what.m_value.c_str(), SR_BINARY_T);
84 }
85
86 void operator()(const enum_& what)
87 {
88 v->set(xpath.c_str(), what.m_value.c_str(), SR_ENUM_T);
89 }
90
91 void operator()(const identityRef_& what)
92 {
93 v->set(xpath.c_str(), (what.m_prefix->m_name + what.m_value).c_str(), SR_IDENTITYREF_T);
94 }
95
Jan Kundrát379bb572020-05-07 03:23:13 +020096 void operator()(const empty_)
97 {
98 v->set(xpath.c_str(), nullptr, SR_LEAF_EMPTY_T);
99 }
100
Jan Kundrátbb525b42020-02-04 11:56:59 +0100101 void operator()(const std::string& what)
102 {
103 v->set(xpath.c_str(), what.c_str());
104 }
105
Václav Kubernát19097f32020-10-05 10:08:29 +0200106 void operator()(const bits_& what)
107 {
108 std::stringstream ss;
109 std::copy(what.m_bits.begin(), what.m_bits.end(), std::experimental::make_ostream_joiner(ss, " "));
110 v->set(xpath.c_str(), ss.str().c_str());
Václav Kubernát19097f32020-10-05 10:08:29 +0200111 }
112
Jan Kundrátbb525b42020-02-04 11:56:59 +0100113 template <typename Type>
114 void operator()(const Type what)
115 {
116 v->set(xpath.c_str(), what);
117 }
118
119 void operator()([[maybe_unused]] const special_ what)
120 {
121 throw std::logic_error("Attempted to create a SR val from a special_ value");
122 }
123
124 ::sysrepo::S_Val v;
125 std::string xpath;
126};
127
Václav Kubernát654303f2020-07-31 13:16:54 +0200128class OperationalDataCallback {
Jan Kundrátbb525b42020-02-04 11:56:59 +0100129public:
130 OperationalDataCallback(const DataSupplier& dataSupplier)
131 : m_dataSupplier(dataSupplier)
132 {
133 }
Václav Kubernát654303f2020-07-31 13:16:54 +0200134 int operator()(
Václav Kubernátb4e5b182020-11-16 19:55:09 +0100135 [[maybe_unused]] sysrepo::S_Session sess,
136 [[maybe_unused]] const char* module_name,
137 const char* path,
138 [[maybe_unused]] const char* request_xpath,
139 [[maybe_unused]] uint32_t request_id,
140 libyang::S_Data_Node& parent)
Jan Kundrátbb525b42020-02-04 11:56:59 +0100141 {
Václav Kubernát654303f2020-07-31 13:16:54 +0200142 auto data = m_dataSupplier.get_data(path);
143 libyang::S_Data_Node res;
144 for (const auto& [p, v] : data) {
145 if (!res) {
146 res = std::make_shared<libyang::Data_Node>(
Václav Kubernátb4e5b182020-11-16 19:55:09 +0100147 sess->get_context(),
148 p.c_str(),
149 v.type() == typeid(empty_) ? nullptr : leafDataToString(v).c_str(),
150 LYD_ANYDATA_CONSTSTRING,
151 0);
Václav Kubernát654303f2020-07-31 13:16:54 +0200152 } else {
153 res->new_path(
Václav Kubernátb4e5b182020-11-16 19:55:09 +0100154 sess->get_context(),
155 p.c_str(),
156 v.type() == typeid(empty_) ? nullptr : leafDataToString(v).c_str(),
157 LYD_ANYDATA_CONSTSTRING,
158 0);
Václav Kubernát654303f2020-07-31 13:16:54 +0200159 }
Jan Kundrátbb525b42020-02-04 11:56:59 +0100160 }
Václav Kubernát654303f2020-07-31 13:16:54 +0200161 parent = res;
Jan Kundrátbb525b42020-02-04 11:56:59 +0100162 return SR_ERR_OK;
163 }
Václav Kubernátb4e5b182020-11-16 19:55:09 +0100164
Jan Kundrátbb525b42020-02-04 11:56:59 +0100165private:
166 const DataSupplier& m_dataSupplier;
167};
168
Václav Kubernát654303f2020-07-31 13:16:54 +0200169OperationalDataSubscription::OperationalDataSubscription(const std::string& moduleName, const std::string& path, const DataSupplier& dataSupplier)
170 : m_connection(std::make_shared<sysrepo::Connection>())
Jan Kundrátbb525b42020-02-04 11:56:59 +0100171 , m_session(std::make_shared<sysrepo::Session>(m_connection))
172 , m_subscription(std::make_shared<sysrepo::Subscribe>(m_session))
Jan Kundrátbb525b42020-02-04 11:56:59 +0100173{
Václav Kubernát654303f2020-07-31 13:16:54 +0200174 m_subscription->oper_get_items_subscribe(moduleName.c_str(), OperationalDataCallback{dataSupplier}, path.c_str());
Jan Kundrátbb525b42020-02-04 11:56:59 +0100175}