Skip to content

sysrepo/sysrepo-cpp

Repository files navigation

C++ bindings for sysrepo

License Gerrit Zuul CI

sysrepo-cpp are object-oriented bindings of the sysrepo library. It uses RAII for automatic memory management.

Dependencies

  • sysrepo - the devel branch (even for the master branch of sysrepo-cpp)
  • libyang-cpp - C++ bindings for libyang
  • C++20 compiler (e.g., GCC 10.x+, clang 10+)
  • CMake 3.19+
  • optionally for built-in tests, Doctest as a C++ unit test framework
  • optionally for built-in tests, trompeloeil for mock objects in C++
  • optionally for the docs, Doxygen

Building

sysrepo-cpp uses CMake for building. The standard way of building sysrepo-cpp looks like this:

mkdir build
cd build
cmake ..
make
make install

Usage

Differences from the previous sysrepo C++ bindings

  • Most of the classes in sysrepo-cpp are not directly instantiated by the user, and are instead returned by methods. The only class directly instantiated by the user is the sysrepo::Connection class.
  • The classes are no longer wrapped by std::shared_ptr. However, they are still copyable and one can have multiple instances of, i.e., sysrepo::Session that refer to the same session. Memory management will still work automatically.

Connections and sessions

The core classes for sysrepo-cpp are sysrepo::Connection and sysrepo::Session. Creating those is straightforward.

auto session = sysrepo::Connection{}.sessionStart();

Examples of simple usage

These are some of the most typical operations supported by sysrepo-cpp.

Editing data and retrieving data

auto session = sysrepo::Connection{}.sessionStart();
session.setItem("/module:myCont/myLeaf", "some-value");
session.applyChanges();

if (auto data = session.getData("/module:myCont/myLeaf")) {
    // `data` points to "/module:myCont", to get the leaf, we need to use findPath
    auto leaf = data.findPath("/module:myCont/myLeaf");
    std::cout << leaf->asTerm().valueStr() << "\n";
} else {
    std::cout << "no data\n";
}

Note: sysrepo::Session::getData always returns the first top-level node of the data that corresponds to the XPath you provided. You might need to use the findPath method on data to get the actual node you wanted.

Creating a subscription for module changes

sysrepo::ModuleChangeCb moduleChangeCb = [] (auto session, auto, auto, auto, auto, auto) {
    for (const auto& change : session.getChanges()) {
        // do stuff
    }
    return sysrepo::ErrorCode::Ok;
};

auto session = sysrepo::Connection{}.sessionStart();
auto sub = sess.onModuleChange("my-module-name", moduleChangeCb);
sub.onRPCAction(...);

Using sysrepo-cpp in your classes

In C++, one usually wants to create a class that groups all of the sysrepo-cpp classes, mainly sessions and subscriptions. Here is an example of such class:

class SysrepoManager {
public:
    SysrepoManager()
        : m_sess(sysrepo::Connection{}.sessionStart())
        , m_sub(/*???*/) // How to initialize this?
    {
    }

private:
    sysrepo::Session m_sess;
    sysrepo::Subscription m_sub;
};

The example illustrates a small caveat of the sysrepo::Subscription class: it is not possible to have an "empty" instance of it. Every sysrepo::Subscription instance must already point to a valid subscription. There are two ways of solving this:

  • Just initialize the m_sub field in the member initializer list. This works if one wants to immediately subscribe to something on the creation of the example class.
  • If actual empty subscriptions are needed std::optional<sysrepo::Subscription> can be used as the type of m_sub. This enables having no active subscriptions, however, when actually creating subscriptions, the first call must use m_sess and any following should use the m_sub. Example:
    m_sub = m_sess.onModuleChange(...);
    m_sub.onRPCAction(...);
    m_sub.onModuleChange(...);

For more examples, check out the examples/ and the tests/ directory.

Contributing

The development is being done on Gerrit here. Instructions on how to submit patches can be found here. GitHub Pull Requests are not used.