Skip to content
Merged
4 changes: 2 additions & 2 deletions cmake/redis-plus-plus.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ set(REDIS_PLUS_PLUS_BUILD_TEST OFF CACHE BOOL "" FORCE)
FetchContent_Declare(redis-plus-plus
GIT_REPOSITORY https://github.com/sewenew/redis-plus-plus.git
# Post 1.3.15. Required to support FetchContent post 1.3.7 where it was broken.
GIT_TAG 84f37e95d9112193fd433f65402d3d183f0b9cf7
GIT_SHALLOW TRUE
GIT_TAG fc67c2ebf929ae2cf3b31d959767233f39c5df6a
GIT_SHALLOW FALSE
)

FetchContent_MakeAvailable(redis-plus-plus)
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include <launchdarkly/server_side/bindings/c/config/config.h>
#include <launchdarkly/server_side/bindings/c/config/lazy_load_builder/lazy_load_builder.h>
#include <launchdarkly/server_side/bindings/c/hook.h>

#include <launchdarkly/bindings/c/config/logging_builder.h>
#include <launchdarkly/bindings/c/export.h>
Expand Down Expand Up @@ -514,6 +515,25 @@ LD_EXPORT(void)
LDServerConfigBuilder_Logging_Custom(LDServerConfigBuilder b,
LDLoggingCustomBuilder custom_builder);

/**
* Registers a hook with the SDK.
*
* Hooks allow you to instrument SDK behavior for logging, analytics,
* or distributed tracing (e.g. OpenTelemetry).
*
* Multiple hooks can be registered. They execute in the order registered.
*
* LIFETIME: The hook struct is copied during this call. The Name string
* must remain valid until LDServerConfigBuilder_Build() is called.
* UserData and function pointers must remain valid for the SDK lifetime.
*
* @param builder Configuration builder. Must not be NULL.
* @param hook Hook to register. The struct is copied. Must not be NULL.
*/
LD_EXPORT(void)
LDServerConfigBuilder_Hooks(LDServerConfigBuilder builder,
struct LDServerSDKHook hook);

/**
* Creates an LDClientConfig. The builder is automatically freed.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/**
* @file evaluation_series_context.h
* @brief C bindings for read-only evaluation context passed to hooks.
*
* EvaluationSeriesContext provides information about a flag evaluation
* to hook callbacks. All data is read-only and valid only during the
* callback execution.
*
* LIFETIME:
* - All context parameters are temporary - valid only during callback
* - Do not store pointers to context data
* - Copy any needed data (strings, values) if you need to retain it
*/

#pragma once

#include <launchdarkly/bindings/c/export.h>
#include <launchdarkly/server_side/bindings/c/hook_context.h>
#include <launchdarkly/bindings/c/value.h>
#include <launchdarkly/bindings/c/context.h>

// No effect in C++, but we want it for C.
// ReSharper disable once CppUnusedIncludeDirective
#include <stdbool.h> // NOLINT(*-deprecated-headers)

#ifdef __cplusplus
extern "C" {
#endif

typedef struct p_LDServerSDKEvaluationSeriesContext* LDServerSDKEvaluationSeriesContext;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, there was a mistake with the syntax of the clang-tidy suppression in the base binding implementations. Which result in suppressing all tidy messages.

We are not doing that here, and the result is that these opaque struct definitions were encountering: https://clang.llvm.org/extra/clang-tidy/checks/bugprone/reserved-identifier.html

Which isn't going to be a problem because the compiler isn't going to spontaneously reserve these very specific names.

But to appease it here I have started with p_. This first name isn't used by calling code, but we just want it to not look like it should be used either.


/**
* @brief Get the flag key being evaluated.
*
* @param eval_context Evaluation context. Must not be NULL.
* @return Flag key as null-terminated UTF-8 string. Valid only during
* the callback execution. Must not be freed.
*/
LD_EXPORT(char const*)
LDEvaluationSeriesContext_FlagKey(LDServerSDKEvaluationSeriesContext eval_context);

/**
* @brief Get the context (user/organization) being evaluated.
*
* @param eval_context Evaluation context. Must not be NULL.
* @return Context object. Valid only during the callback execution.
* Must not be freed. Do not call LDContext_Free() on this.
*/
LD_EXPORT(LDContext)
LDEvaluationSeriesContext_Context(LDServerSDKEvaluationSeriesContext eval_context);

/**
* @brief Get the default value provided to the variation call.
*
* @param eval_context Evaluation context. Must not be NULL.
* @return Default value. Valid only during the callback execution.
* Must not be freed. Do not call LDValue_Free() on this.
*/
LD_EXPORT(LDValue)
LDEvaluationSeriesContext_DefaultValue(
LDServerSDKEvaluationSeriesContext eval_context);

/**
* @brief Get the name of the variation method called.
*
* Examples: "BoolVariation", "StringVariationDetail", "JsonVariation"
*
* @param eval_context Evaluation context. Must not be NULL.
* @return Method name as null-terminated UTF-8 string. Valid only during
* the callback execution. Must not be freed.
*/
LD_EXPORT(char const*)
LDEvaluationSeriesContext_Method(LDServerSDKEvaluationSeriesContext eval_context);

/**
* @brief Get the hook context provided by the caller.
*
* This contains application-specific data passed to the variation call,
* such as OpenTelemetry span parents.
*
* @param eval_context Evaluation context. Must not be NULL.
* @return Hook context. Valid only during the callback execution.
* Must not be freed. Do not call LDHookContext_Free() on this.
*/
LD_EXPORT(LDHookContext)
LDEvaluationSeriesContext_HookContext(
LDServerSDKEvaluationSeriesContext eval_context);

/**
* @brief Get the environment ID, if available.
*
* The environment ID is only available after SDK initialization completes.
* Returns NULL if not yet available.
*
* @param eval_context Evaluation context. Must not be NULL.
* @return Environment ID as null-terminated UTF-8 string, or NULL if not
* available. Valid only during the callback execution. Must not
* be freed.
*/
LD_EXPORT(char const*)
LDEvaluationSeriesContext_EnvironmentId(
LDServerSDKEvaluationSeriesContext eval_context);

#ifdef __cplusplus
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
/**
* @file evaluation_series_data.h
* @brief C bindings for hook data passed between evaluation stages.
*
* EvaluationSeriesData is mutable data that hooks can use to pass information
* from beforeEvaluation to afterEvaluation. This is useful for:
* - Storing timing information
* - Passing span contexts for distributed tracing
* - Accumulating custom metrics
*
* LIFETIME AND OWNERSHIP:
* - Data returned from hook callbacks transfers ownership to the SDK
* - Data received in callbacks can be modified and returned (ownership transfer)
* - Keys are copied by the SDK
* - Values retrieved with GetValue() are temporary - valid only during callback
* - Do not call LDValue_Free() on values retrieved with GetValue()
* - Values stored with SetValue() are copied into the data object
* - Pointers (void*) lifetime is managed by the application
*
* BUILDER PATTERN:
* To modify data, use LDEvaluationSeriesData_NewBuilder() to create a builder,
* make changes, then build a new data object.
*/

#pragma once

#include <launchdarkly/bindings/c/export.h>
#include <launchdarkly/bindings/c/context.h>

// No effect in C++, but we want it for C.
// ReSharper disable once CppUnusedIncludeDirective
#include <stdbool.h> // NOLINT(*-deprecated-headers)
// ReSharper disable once CppUnusedIncludeDirective
#include <stddef.h> // NOLINT(*-deprecated-headers)

#ifdef __cplusplus
extern "C" {
#endif

typedef struct p_LDServerSDKEvaluationSeriesData* LDServerSDKEvaluationSeriesData;
typedef struct p_LDEvaluationSeriesDataBuilder* LDServerSDKEvaluationSeriesDataBuilder;


/**
* @brief Create a new empty evaluation series data.
*
* @return New data object. Must be freed with LDEvaluationSeriesData_Free()
* or transferred to SDK via hook callback return.
*/
LD_EXPORT(LDServerSDKEvaluationSeriesData)
LDEvaluationSeriesData_New(void);

/**
* @brief Get a Value from the evaluation series data.
*
* LIFETIME: Returns a temporary value valid only during the callback.
* Do not call LDValue_Free() on the returned value.
*
* USAGE:
* @code
* LDValue value;
* if (LDEvaluationSeriesData_GetValue(data, "timestamp", &value)) {
* // Use value (valid only during callback)
* double timestamp = LDValue_GetNumber(value);
* // Do NOT call LDValue_Free(value)
* }
* @endcode
*
* @param data Data object. Must not be NULL.
* @param key Key to look up. Must be null-terminated UTF-8 string.
* Must not be NULL.
* @param out_value Pointer to receive the value. Must not be NULL.
* Set to a temporary LDValue (valid only during callback).
* Do not call LDValue_Free() on this value.
* @return true if key was found and contains a Value, false otherwise.
*/
LD_EXPORT(bool)
LDEvaluationSeriesData_GetValue(LDServerSDKEvaluationSeriesData data,
char const* key,
LDValue* out_value);

/**
* @brief Get a pointer from the evaluation series data.
*
* Retrieves a pointer previously stored with
* LDEvaluationSeriesDataBuilder_SetPointer().
*
* USAGE - OpenTelemetry span:
* @code
* void* span;
* if (LDEvaluationSeriesData_GetPointer(data, "span", &span)) {
* // Cast and use span
* MySpan* typed_span = (MySpan*)span;
* }
* @endcode
*
* @param data Data object. Must not be NULL.
* @param key Key to look up. Must be null-terminated UTF-8 string.
* Must not be NULL.
* @param out_pointer Pointer to receive the pointer value. Must not be NULL.
* Set to NULL if key not found.
* @return true if key was found and contains a pointer, false otherwise.
*/
LD_EXPORT(bool)
LDEvaluationSeriesData_GetPointer(LDServerSDKEvaluationSeriesData data,
char const* key,
void** out_pointer);

/**
* @brief Create a builder from existing data.
*
* Creates a builder initialized with the contents of the data object.
* Use this to add or modify entries in the data.
*
* USAGE:
* @code
* LDServerSDKEvaluationSeriesDataBuilder builder =
* LDEvaluationSeriesData_NewBuilder(input_data);
* LDEvaluationSeriesDataBuilder_SetValue(builder, "key", value);
* return LDEvaluationSeriesDataBuilder_Build(builder);
* @endcode
*
* @param data Data to copy into builder. May be NULL (creates empty builder).
* @return Builder object. Must be freed with
* LDEvaluationSeriesDataBuilder_Free() or consumed with
* LDEvaluationSeriesDataBuilder_Build().
*/
LD_EXPORT(LDServerSDKEvaluationSeriesDataBuilder)
LDEvaluationSeriesData_NewBuilder(LDServerSDKEvaluationSeriesData data);

/**
* @brief Free evaluation series data.
*
* Only call this if you created the data and are not returning it from
* a hook callback. Data returned from callbacks is owned by the SDK.
*
* @param data Data to free. May be NULL (no-op).
*/
LD_EXPORT(void)
LDEvaluationSeriesData_Free(LDServerSDKEvaluationSeriesData data);

/**
* @brief Set a Value in the builder.
*
* OWNERSHIP: The value is copied/moved into the builder. You are responsible
* for freeing the original value if needed.
*
* @param builder Builder object. Must not be NULL.
* @param key Key for the value. Must be null-terminated UTF-8 string.
* Must not be NULL. The key is copied.
* @param value Value to store. Must not be NULL. The value is copied/moved.
*/
LD_EXPORT(void)
LDEvaluationSeriesDataBuilder_SetValue(LDServerSDKEvaluationSeriesDataBuilder builder,
char const* key,
LDValue value);

/**
* @brief Set a pointer in the builder.
*
* Stores an application-specific pointer. Useful for storing objects like
* OpenTelemetry spans that need to be passed from beforeEvaluation to
* afterEvaluation.
*
* LIFETIME: The pointer lifetime must extend through the evaluation series
* (from beforeEvaluation through afterEvaluation).
*
* EXAMPLE - OpenTelemetry span:
* @code
* MySpan* span = start_span();
* LDEvaluationSeriesDataBuilder_SetPointer(builder, "span", span);
* @endcode
*
* @param builder Builder object. Must not be NULL.
* @param key Key for the pointer. Must be null-terminated UTF-8 string.
* Must not be NULL. The key is copied.
* @param pointer Pointer to store. May be NULL. Lifetime managed by caller.
*/
LD_EXPORT(void)
LDEvaluationSeriesDataBuilder_SetPointer(
LDServerSDKEvaluationSeriesDataBuilder builder,
char const* key,
void* pointer);

/**
* @brief Build the evaluation series data.
*
* Consumes the builder and creates a data object. After calling this,
* do not call LDEvaluationSeriesDataBuilder_Free() on the builder.
*
* @param builder Builder to consume. Must not be NULL.
* @return Data object. Must be freed with LDEvaluationSeriesData_Free()
* or transferred to SDK via hook callback return.
*/
LD_EXPORT(LDServerSDKEvaluationSeriesData)
LDEvaluationSeriesDataBuilder_Build(LDServerSDKEvaluationSeriesDataBuilder builder);

/**
* @brief Free a builder without building.
*
* Only call this if you did not call LDEvaluationSeriesDataBuilder_Build().
*
* @param builder Builder to free. May be NULL (no-op).
*/
LD_EXPORT(void)
LDEvaluationSeriesDataBuilder_Free(LDServerSDKEvaluationSeriesDataBuilder builder);

#ifdef __cplusplus
}
#endif
Loading
Loading