blob: d4827bb5af836ff2993d2c51d9ccac6609f4831b [file] [log] [blame]
/*
* Copyright (C) 2018 CESNET, https://photonics.cesnet.cz/
* Copyright (C) 2018 FIT CVUT, https://fit.cvut.cz/
*
* Written by Václav Kubernát <kubervac@fit.cvut.cz>
*
*/
#include <experimental/iterator>
#include <sstream>
#include <sysrepo-cpp/Session.hpp>
#include "sysrepo_subscription.hpp"
#include "utils.hpp"
class MyCallback {
public:
MyCallback(const std::string& moduleName, Recorder* rec)
: m_moduleName(moduleName)
, m_recorder(rec)
{
}
sysrepo::ErrorCode operator()(
sysrepo::Session sess,
uint32_t /* sub_id */,
std::string_view module_name,
std::optional<std::string_view> /* sub_xpath */,
sysrepo::Event event,
uint32_t /* request_id */)
{
using namespace std::string_literals;
if (event == sysrepo::Event::Change) {
return sysrepo::ErrorCode::Ok;
}
for (const auto& it : sess.getChanges(("/"s + module_name.data() + ":*//.").c_str())) {
auto xpath = it.node.path();
std::optional<std::string> oldValue;
std::optional<std::string> newValue;
if (it.operation == sysrepo::ChangeOperation::Deleted) {
oldValue = it.node.schema().nodeType() == libyang::NodeType::Leaf || it.node.schema().nodeType() == libyang::NodeType::Leaflist ?
std::optional<std::string>{it.node.asTerm().valueStr()} :
std::nullopt;
} else {
oldValue = std::optional<std::string>{it.previousValue};
newValue = it.node.schema().nodeType() == libyang::NodeType::Leaf || it.node.schema().nodeType() == libyang::NodeType::Leaflist ?
std::optional<std::string>{it.node.asTerm().valueStr()} :
std::nullopt;
}
std::optional<std::string> previousList;
if (it.previousList) {
previousList = std::string{*it.previousList};
}
m_recorder->write(it.operation, std::string{xpath}, oldValue, newValue, previousList);
}
return sysrepo::ErrorCode::Ok;
}
private:
std::string m_moduleName;
Recorder* m_recorder;
};
Recorder::~Recorder() = default;
DataSupplier::~DataSupplier() = default;
SysrepoSubscription::SysrepoSubscription(const std::string& moduleName, Recorder* rec, sysrepo::Datastore ds)
: m_subscription([&moduleName, &rec, ds] { // This is an immediately invoked lambda.
return sysrepo::Connection{}.sessionStart(ds).onModuleChange(moduleName.c_str(),
rec ? sysrepo::ModuleChangeCb{MyCallback{moduleName, rec}}
: sysrepo::ModuleChangeCb{[](auto, auto, auto, auto, auto, auto) { return sysrepo::ErrorCode::Ok; }});
}())
{
}
class OperationalDataCallback {
public:
OperationalDataCallback(const DataSupplier& dataSupplier)
: m_dataSupplier(dataSupplier)
{
}
sysrepo::ErrorCode operator()(
sysrepo::Session session,
[[maybe_unused]] uint32_t subscriptionId,
[[maybe_unused]] std::string_view moduleName,
std::optional<std::string_view> subXPath,
[[maybe_unused]] std::optional<std::string_view> requestXPath,
[[maybe_unused]] uint32_t requestId,
std::optional<libyang::DataNode>& output)
{
auto data = m_dataSupplier.get_data(subXPath->data());
for (const auto& [p, v] : data) {
if (!output) {
output = session.getContext().newPath(p.c_str(), v.type() == typeid(empty_) ? nullptr : leafDataToString(v).c_str());
} else {
output->newPath(p.c_str(), v.type() == typeid(empty_) ? nullptr : leafDataToString(v).c_str());
}
}
return sysrepo::ErrorCode::Ok;
}
private:
const DataSupplier& m_dataSupplier;
};
OperationalDataSubscription::OperationalDataSubscription(const std::string& moduleName, const std::string& path, const DataSupplier& dataSupplier)
: m_subscription(sysrepo::Connection{}.sessionStart().onOperGet(moduleName.c_str(), OperationalDataCallback{dataSupplier}, path.c_str()))
{
}