1.2. SDK core elements
This chapter outlines the common, core elements and conventions used throughout the SDK, for example errors, exceptions, and handling asynchronous operations.
1.2.1. Boost C++ library
The Proximie SDK minimises the use of external libraries for reasons of simplicity and mitigation of security/vulnerability risks. We use various Boost libraries as they are highly respected, robust, well-tested and comprehensively assessed for vulnerabilities. The sections in this chapter will give details when they utilise Boost for features and functionality.
1.2.2. Error handling
Exceptions
The Proximie SDK only throws exceptions for truly exceptional or critical conditions such as out of memory. Otherwise, errors are either returned from function calls or as parameters in callbacks etc.
Error codes
The SDK uses error codes based on Boost’s extensible error reporting
(see https://www.boost.org/doc/libs/release/libs/system/) using error_code
.
This is aliased into the Proximie namespace as Proximie::error_code
for
convenience. Error codes allow domain-specific errors to be defined and then handled
by the client application. Both Boost and STL error codes work in the same way;
they encapsulate an error category and a numeric error value.
Error codes can simply be if
-tested to check if there is an error value:
void onCompleted(Proximie::error_code error) {
if (!error) {
// Successful, no error
return;
}
// Handle error...
}
All error categories defined in the Proximie SDK have a static function to obtain the category, allowing error handlers to test the category for an error:
if (error.category() == Proximie::PxMedia::PxMediaErrorCategory::category()) {
// Handle media error...
Otherwise, each error category code can be type-safely compared:
if (error == Proximie::PxMedia::PxMediaErrorCode::InvalidSession) {
// Handle invalid media session...
Outcomes and results
Where a function call may return a failure condition, the SDK uses Boost’s Outcome
library (see https://www.boost.org/doc/libs/release/libs/outcome/).
Again, this is aliased into the Proximie namespace as Proximie::outcome
for convenience. An outcome result
represents either a successful return
(which may be some value type or simply void
) or an error in the form
of an error_code
as discussed above.
Refer to the Boost documentation for details, but briefly, given some result-return function:
Proximie::outcome::result<int> getSomeIntResult();
The result is [[nodiscard]]
, which allows the compiler to detect if the
caller accidentally forget to check the return value. You can check for a successful
result with a simple if
on the result itself, or with has_error
and has_value
functions.
auto result = getSomeIntResult();
if (result) {
int value = result.value();
// Do something with the value...
} else {
Proximie::error_code error = result.error();
// Handle the error...
}
if (result.has_error()) {
Proximie::error_code error = result.error();
// Handle the error...
}
if (result.has_value()) {
int value = result.value();
// Do something with the value...
}
1.2.3. Object lifetimes
The Proximie SDK makes extensive use of STL “smart pointers”,
namely std::shared_ptr
and std::unique_ptr
. A common
pattern for SDK classes to have private constructors and a static factory
create
function that returns the smart pointer.
The SDK makes use of the concept of “not-null” pointers, which are part of the C++ Core Guidelines. See the section on not-null in the guidelines. The SDK implementation is taken from the Guidelines support library.
Due to the asynchronous nature of the SDK, shared pointers are commonly used for objects that instigate asynchronous operations. This allows an object’s creator to free their local pointer without causing the object to be destroyed whilst an async operation is still in flight. The operations themselves keep the object alive, and when all references are freed (i.e. there are guaranteed no more async operations), the object can safely be freed. This is why some object types that one might expect to use unique (i.e. one and only one owner) pointers, need to use shared pointers.
1.2.4. Asynchronous I/O
The SDK provides a broad set of features, many of which are asynchronous - e.g. HTTP requests, WebSockets, communication with various Proximie services and so on.
Underpinning the async functionality is Boost’s Asio library (see https://live.boost.org/doc/libs/release/doc/html/boost_asio.html). For the most part SDK clients do not need to be concerned by the underlying implementation.
For more details, see Async operations & threading.