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:
- Rust SDK: https://crates.io/crates/avassa-client
- Python SDK: https://pypi.org/project/avassa-client/
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:
- Boost for networking: https://www.boost.org/
- Niels Lohmann’s JSON library for JSON handling: https://github.com/nlohmann/json
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
- https://docs.avassa.io/how-to/policy#control-application-access-to-apis
- https://docs.avassa.io/tutorials/developing-with-strongbox-edge#authentication
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:
- https://docs.avassa.io/reference/volga-websocket-api#open-producer
- https://docs.avassa.io/reference/volga-websocket-api#open-consumer
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:
- https://docs.avassa.io/reference/volga-websocket-api#more
- https://docs.avassa.io/reference/volga-websocket-api#volga-message
- https://docs.avassa.io/reference/volga-websocket-api#ack
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