10Duke Scale C++ SDK
Loading...
Searching...
No Matches
Client Concepts

This provides a high-level overview of the 10Duke Scale C++ SDK and introduces some fundamental concepts.

The client is stateful

Factory functions are used to create the client. If you only require the checkout/heartbeat/release functionality with license keys (see Use license key for licensing operations), you can use tenduke::se::TendukeClient. If you are using identity-based licensing, use tenduke::se::TendukeClientWithOIDCSession.

Both of these clients are stateful, and you must keep the instance alive for the duration of the application.

TendukeClient maintains a lease cache: all checked-out license leases are held in a memory-based cache. You do not need to manually track the leases. All lease operations (heartbeat, release) operate through the cache.

TendukeClientWithOIDCSession extends TendukeClient and adds user login session management. See the links above for further information on the clients.

Save and restore the client state

Since the client is stateful, we recommend that you save the client state to a persistent storage. For example, when the application is about to close, you can request the state to be serialized. You can serialize the state after any license-related API call. This protects the state against any abnormal application termination (for example, a power loss). The state is serialized into a JSON string that you can store, for example, on disk. The JSON format is not documented, and any modification of the JSON outside the client is not supported.

To prevent anyone from tampering the state, we strongly recommend that you encrypt the serialized state before storing it. The client does not support encryption or decryption of the state.

When the application restarts, it reads and decrypts the stored state, and passes the string in the initialStateAsJSON parameter to the factory functions that create the client.

The stored state contains OIDC/OAuth configuration, OIDC session state (for example, an access token, ID token), valid (unexpired) license leases, and license token verification keys.

For example, to serialize current state of the client, execute the following:

std::shared_ptr<::TendukeClient> tendukeClient = ...;
std::string serializedState = tendukeClient->serializeState();

To restore the client state, pass the serialized state to the factory function when creating the client:

std::string serializedState = ...; // Read the state from somewhere
auto tenduke = ::createTendukeClientForBrowserUsingAutodiscovery(
"stateful-client-demo/0.0.1-alpha-1",
::tenduke::se::BackendConfiguration("https://scale.10duke.com"),
::tenduke::se::ClientPropertiesBuilder().version("0.0.1-alpha-1").build(),
"https://genco.10duke.net/.well-known/openid-configuration",
::BrowserAuthenticationConfig("demo", "http://localhost/login", httpMessageAfterLogin),
serializedState // pass the state here
);

Use 10Duke Scale REST APIs

If you want to use 10Duke Scale REST APIs that don't yet have a C++ implementation, you must authorize the HTTP requests using an OIDC ID token. This requires using identity-based licensing.

To get the ID token, use the tenduke::oidc::OIDCState.getIdToken() method. Authenticate the request by adding an HTTP header named Authorization with the value IdToken serialized-id-token-value. Replace serialized-id-token-value with the serialized ID token value (obtained via the tenduke::oidc::IdToken.getSerialized() method).

For example:

std::shared_ptr<::tenduke::se::TendukeClientWithOIDCSession> tendukeClient = ...; // Client created earlier
// Make sure that user has a valid session.
// If the user does not have valid session, this call will either refresh the session or re-login the user
tendukeClient->oidcSession->ensureValidSession();
// Get the id-token:
auto idToken = tendukeClient->oidcSession->getOIDCState()->getIdToken();
auto serializedIdToken = idToken.getSerialized();
auto headerValue = "IdToken " + serializedIdToken;

Errors

Error conditions are reported using C++ exceptions. All exceptions thrown by the client inherit from the tenduke::TendukeException class. As a general rule of thumb, an exception can be thrown if a method or function requires network access. Parsing JSON or JWTs, or doing cryptography operations can also throw exceptions. Most methods try to document thrown exceptions, but this is not totally reliable.

Some network exceptions are handled behind the scenes, but there are still several conditions where the exception is propagated to the caller of the method. Network exceptions are caused either by permanent conditions (for example, an invalid URL has been configured) or by temporary conditions (for example, the network is temporarily down, a server is in maintenance, or a server is out of resources). There is currently no retry logic in the client for temporary network issues.

Note that certain licensing-related error conditions do not throw exceptions. For example, if you try to check out a seat in a license and there are no seats available, the client does not throw an exception. See tenduke::se::licensing::LicensingClient for more information.

See also API error handling in the 10Duke Scale documentation.

High-level vs low-level

The client is built using layers. Most users can use the high-level client that abstracts away much of the complexities of request authentication. For more control, you can use the low-level client. For example, the high-level tenduke::se::licensing::DefaultLicensingClient uses a lower level tenduke::se::licensing::rest::ScaleLicensingApiImpl. The low-level client performs the actual network call, handling request parametrization and response parsing. The high-level client manages the OIDC user session state and lease cache.

The low-level clients are currently not thoroughly documented. However, we strive to keep their interface stable and ensure it matches the REST API.