How to Integrate Your C/C++ Applications with the Avassa Edge Platform

C++ programmers, we haven’t forgotten about you!

We have several customers with an active C/C++ code base. It’s therefore natural the question comes up on how to integrate that code with the Avassa Edge Platform. Generally, you don’t need to integrate the code itself into the Avassa Edge Platform; just package the code into a container, and you’re good. In certain cases, you may want to use our REST APIs, though.

In this post, I will show you how it’s done

Avassa Platform SDKs and C++ Integration Options

The Avassa Edge Platform comes with a comprehensive REST API, https://avassa-api.redoc.ly/. We also offer two officially supported SDKs that bind to the REST API:

Both are used both internally at Avassa and with our customers. While a C++ SDK does not exist yet, the entire Avassa Edge Platform is fully API-driven, making C++ integrations straightforward using standard HTTP and WebSocket libraries.

The most common scenario for integration is with our built-in pub/sub bus, the code below shows how to set up a producer and consumer.

For simplicity, we use:

Authenticating Against the Avassa Edge Platform API

auto login(ssl_socket_t &ssl_sock, std::string_view hostname) {
    std::string endpoint;
    std::string payload;
    if (auto sid = std::getenv("APPROLE_SECRET_ID"); sid != nullptr) {
      std::println("Logging in using approle");
      std::string secret_id = std::string(sid);

      // NOTE: We set role-id to the value from `approle.yml`
      json login_payload = {{"role-id", "22970b5b-7c73-4b23-8689-2a8d686ca01e"},
                            {"secret-id", secret_id}};
      payload = login_payload.dump();
      endpoint = "/v1/approle-login";
    } else if (auto username = std::getenv("SUPD_USER"); username != nullptr) {
      std::println("Logging in user: {}", username);
      json login_payload = {
          {"username", std::string_view(username)},
          {"password", std::string_view(std::getenv("SUPD_PASSWORD"))}};
      payload = login_payload.dump();
      endpoint = "/v1/login";
    } else {
      throw std::runtime_error("No authentication specified");
    }

    http::request<http::string_body> req(http::verb::post, endpoint, HTTP_VER);
    req.set(http::field::host, hostname);
    req.body() = payload;
    req.prepare_payload();

    req.set(http::field::content_type, "application/json");

    http::write(ssl_sock, req);

    boost::beast::flat_buffer buffer;
    http::response<http::string_body> res;
    http::read(ssl_sock, buffer, res);
    auto response = json::parse(res.body());

    auto token = response.at("token").get<std::string>();
    // NOTE: In a realistic application, you should renew the token
    // see  "expires-in" and/or "expires" in the returned payload

    return token;
  }

The code above either read username/password or an application role’s secret ID from the environment. Username/password is great for testing, while app roles are used when deploying on the Avassa Edge Platform. See the following links for more information

Using the Avassa Pub/Sub Bus from C++

Communication with the Avassa Edge Platform pub/sub bus is typically done over websockets. The code below shows how to open a producer and a consumer websocket

    auto producer_ws = create_websocket(ioc, ssl_ctx, resolved, hostname, token);

    json open_cmd = {
        {"op", "open-producer"},
        {"location", "local"},
        {"topic", TOPIC},
        {"on-no-exists", "create"},
        {"create-options", {{"replication-factor", 1}, {"format", "json"}}},
        {"name", "cpp-producer"}};

    producer_ws.write(boost::asio::buffer(open_cmd.dump()));

    wait_volga_ok(producer_ws);

    std::println("Setting up consumer");
    auto consumer_ws = create_websocket(ioc, ssl_ctx, resolved, hostname, token);
    open_cmd = {{"op", "open-consumer"},  {"location", "local"},
                {"topic", TOPIC},         {"position", "unread"},
                {"on-no-exists", "wait"}, {"name", "cpp-consumer"}};

    consumer_ws.write(boost::asio::buffer(open_cmd.dump()));

    wait_volga_ok(consumer_ws);

See the following links for options when opening producers/consumers:

Producing Data from C++

Producing data is simple

        json payload = {{"msg-id", idx++}};
        json produce = {{"op", "produce"}, {"payload", payload}};

        producer_ws.write(boost::asio::buffer(produce.dump()));

Note that the payload can be any valid JSON object, in this case it’s a simple one.

See:

Consuming data

When consuming, first you need to tell the system that you are ready for messages, in this case we send more=1 which indicates we need a single message.

      // Indicate we want to consume one more message
      json more = {{"op", "more"}, {"n", 1}};

      consumer_ws.write(boost::asio::buffer(more.dump()));

      boost::beast::flat_buffer buffer;
      consumer_ws.read(buffer);
      auto resp = buffer.data();
      auto json_resp = json::parse(boost::asio::buffers_begin(resp),
                                   boost::asio::buffers_end(resp));

      std::println("Message:\\n{}\\n", json_resp.dump(2));

      // Let's ack this message so we don't consume it again
      auto seqno = json_resp.at("seqno").get<uint64_t>();
      json ack = {{"op", "ack"}, {"seqno", seqno}};

      consumer_ws.write(boost::asio::buffer(ack.dump()));

After sending more we simply read messages as they are produces (or older ones we haven’t read yet).

After each message we send an ack indicating we have processed this message and we are not interested in receiving it again in case we reconnect.

See:

Conclusion

Even without a dedicated C++ SDK, integrating C and C++ applications with the Avassa Edge Platform is straightforward thanks to its fully API-driven design. Using Boost for networking and the nlohmann JSON library, you can easily authenticate, interact with the pub/sub bus, and build powerful edge-native C++ components.

If you maintain a C/C++ codebase and want to modernize it for edge workloads, the Avassa APIs provide a clean, flexible path forward.

Sources

https://gitlab.com/avassa-public/avassa-cpp-example