Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: server-side SDK #160

Merged
merged 80 commits into from
Oct 23, 2023
Merged
Changes from 1 commit
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
c417579
feat: add server-sdk subdirectory
cwaldren-ld Jun 12, 2023
c985539
chore: move ItemDescriptor to internal library (#151)
cwaldren-ld Jun 14, 2023
420d7a2
feat: update event processor to handle context key deduplication (#150)
cwaldren-ld Jun 14, 2023
4f89b44
chore: Merge branch 'main' into server-side
kinyoklion Jun 30, 2023
dd174a2
feat: segment data model (#153)
cwaldren-ld Jun 30, 2023
4954f88
feat: flag data model (#156)
cwaldren-ld Jun 30, 2023
f38e038
Merge branch 'main' into server-side
cwaldren-ld Jul 6, 2023
09d2bd6
feat: add Flag model to SDKDataSet (#159)
cwaldren-ld Jul 6, 2023
8367305
chore: Implement architecture diagram for data store. (#161)
kinyoklion Jul 7, 2023
2781af0
fix: Add various missing headers. (#163)
kinyoklion Jul 7, 2023
90627f2
chore: Implement server data source architecture diagram. (#167)
kinyoklion Jul 11, 2023
f2d96a4
feat: Implement basic in-memory store and change handling. (#165)
kinyoklion Jul 12, 2023
3c12979
chore: Refactor to allow sharing data source status and IDataSource. …
kinyoklion Jul 12, 2023
08aaa66
feat: Implement streaming data source. (#179)
kinyoklion Jul 17, 2023
3692736
chore: Update data store updater use reference. (#181)
kinyoklion Jul 17, 2023
ceec434
Merge branch 'main' into server-side
kinyoklion Jul 17, 2023
99dea86
feat: add ContextKind type to data model (#184)
cwaldren-ld Jul 18, 2023
e5992ef
feat: evaluation engine (#183)
cwaldren-ld Jul 18, 2023
bb75d4b
feat: initial pass of server-side Client object (#176)
cwaldren-ld Jul 19, 2023
674c343
feat: Add persistent store core interface. (#187)
kinyoklion Jul 19, 2023
0ead705
fix: EvaluationStack should take ownership of key argument (#190)
cwaldren-ld Jul 19, 2023
30d2e21
feat: Add expiration tracker. (#188)
kinyoklion Jul 19, 2023
213acbd
chore: add event processor architectural diagrams (#192)
cwaldren-ld Jul 20, 2023
0b29ea2
feat: Serialize flags and segments. (#194)
kinyoklion Jul 21, 2023
1f44309
Merge branch 'main' into server-side
cwaldren-ld Aug 16, 2023
a592e87
feat: build server SDK in CI (#198)
cwaldren-ld Aug 21, 2023
275bb66
feat: hello-cpp-server (#202)
cwaldren-ld Aug 23, 2023
9b38361
feat: server-side contract tests (#197)
cwaldren-ld Aug 23, 2023
57c29d8
fix: multi-kind user segment targeting (#206)
cwaldren-ld Aug 24, 2023
ef1061e
fix: handle undefined flag variations in fallthrough (#205)
cwaldren-ld Aug 24, 2023
648e202
Merge branch 'main' into server-side
cwaldren-ld Aug 24, 2023
9edacd1
Merge branch 'main' into server-side
cwaldren-ld Aug 25, 2023
09c74dd
remove contract test branch from server.yml
cwaldren-ld Aug 25, 2023
4ccd79f
fix: refactor Variation methods for correctness & clarity (#203)
cwaldren-ld Aug 25, 2023
a7a9660
Merge branch 'main' into server-side
cwaldren-ld Aug 25, 2023
9ec37f6
refactor: push typechecking of variation methods deeper down (#216)
cwaldren-ld Aug 28, 2023
30bfed2
Merge branch 'main' into server-side
cwaldren-ld Aug 28, 2023
62cb864
Merge branch 'main' into server-side
cwaldren-ld Aug 29, 2023
66b4c83
fix: deserializing certain values leads to infinite loop (#224)
cwaldren-ld Aug 29, 2023
eb1b3ed
feat: add DataSourceStatus() and plumb through IClient interface (#217)
cwaldren-ld Aug 30, 2023
b9c03e2
Merge branch 'main' into server-side
cwaldren-ld Aug 30, 2023
371ab00
refactor: move DataSourceStatus ErrorInfo C Bindings into common (#225)
cwaldren-ld Aug 30, 2023
61ddbe7
add Doxygen config and doc.md
cwaldren-ld Aug 30, 2023
aba2473
chore: add Server-side README (#226)
cwaldren-ld Aug 31, 2023
1538a76
fix: ensure flag updates go through data store updater (#228)
cwaldren-ld Aug 31, 2023
7ab8c1d
Merge branch 'main' into server-side
cwaldren-ld Aug 31, 2023
3669ff5
feat: server-side C bindings (#210)
cwaldren-ld Aug 31, 2023
4889549
feat: plumb server side initial backoff delay (#232)
cwaldren-ld Sep 1, 2023
d0ce48d
add story label to remaining test suppressions:
cwaldren-ld Sep 1, 2023
1db6db9
chore: resolve ValidChar function lint/compile warnings (#234)
cwaldren-ld Sep 5, 2023
5f04888
Merge branch 'main' into server-side
cwaldren-ld Sep 11, 2023
fe9e559
Merge branch 'main' into server-side
cwaldren-ld Sep 14, 2023
61a3bef
use async_connect() instead of run() in streaming data source
cwaldren-ld Sep 15, 2023
ede809d
Merge branch 'main' into server-side
cwaldren-ld Oct 18, 2023
a1751f3
build: fix LD_BUILD_SHARED_LIBS flag usage
cwaldren-ld Oct 18, 2023
32fc0ce
Merge branch 'cw/fix-shared-lib-variable' into server-side
cwaldren-ld Oct 18, 2023
f4c6542
use new cmake variables
cwaldren-ld Oct 18, 2023
6e428b4
one more missing usage
cwaldren-ld Oct 18, 2023
ed49fff
Merge branch 'cw/fix-shared-lib-variable' into server-side
cwaldren-ld Oct 18, 2023
29385ec
fix merge conflicts
cwaldren-ld Oct 18, 2023
f796566
fix hello-c-server compilation
cwaldren-ld Oct 18, 2023
5eeb40e
Merge branch 'main' into server-side
cwaldren-ld Oct 19, 2023
9c9ec0b
update server github workflow to better match client's
cwaldren-ld Oct 19, 2023
7760458
remove old-style user contract test suppressions
cwaldren-ld Oct 19, 2023
b0a6885
fix: enforce validated ContextKind usage in Segment data model (#263)
cwaldren-ld Oct 20, 2023
dc14199
formatting
cwaldren-ld Oct 19, 2023
880ab16
use WriteMinimal where possible for writing JSON
cwaldren-ld Oct 20, 2023
2c494ce
clang format
cwaldren-ld Oct 20, 2023
64ab87d
remove TODO about using initial reconnect delay (implemented)
cwaldren-ld Oct 20, 2023
ce9ae07
remove/resolve some TODOs
cwaldren-ld Oct 20, 2023
e217299
Merge branch 'main' into server-side
cwaldren-ld Oct 20, 2023
a6a7456
fix client-and-server-coexistence linking
cwaldren-ld Oct 20, 2023
9597b29
update client/server readmes and put CMake options in toplevel readme
cwaldren-ld Oct 20, 2023
943d07c
revert change to client data source status state
cwaldren-ld Oct 20, 2023
8179eba
remove unused evaluation detail API & remove implicit bool operator
cwaldren-ld Oct 20, 2023
6f1aba6
Merge branch 'main' into server-side
cwaldren-ld Oct 20, 2023
1da898d
Merge branch 'main' into server-side
cwaldren-ld Oct 20, 2023
df4ef40
add some story links for todos
cwaldren-ld Oct 23, 2023
d7453d3
remove object slicing in asio_event_processor
cwaldren-ld Oct 23, 2023
17a9d38
remove useless inheritance usage in server-side events
cwaldren-ld Oct 23, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat: server-side C bindings (#210)
Implements a set of C bindings for the server-side SDK. 

Missing are flag notifier bindings, but this isn't implemented in the
C++ side yet either.
  • Loading branch information
cwaldren-ld authored Aug 31, 2023
commit 3669ff54add48cd4d8feb67ba2f4bfe6edcb73f3
3 changes: 3 additions & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
add_subdirectory(hello-c-client)
add_subdirectory(hello-cpp-client)
add_subdirectory(hello-cpp-server)
add_subdirectory(hello-c-server)

add_subdirectory(client-and-server-coexistence)
15 changes: 15 additions & 0 deletions examples/client-and-server-coexistence/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Required for Apple Silicon support.
cmake_minimum_required(VERSION 3.19)

project(
LaunchDarklyCClientAndServerCoexistence
VERSION 0.1
DESCRIPTION "LaunchDarkly C Client-side and Server-side SDK coexistence in same application"
LANGUAGES C
)

set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)

add_executable(c-client-and-server main.c)
target_link_libraries(c-client-and-server PRIVATE launchdarkly::client launchdarkly::server launchdarkly::sse launchdarkly::common Threads::Threads)
46 changes: 46 additions & 0 deletions examples/client-and-server-coexistence/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* This application intends to verify that the symbols from the
* client-side and server-side SDKs do not clash, thus enabling both SDKs to be
* used within the same application.
*/

#include <launchdarkly/client_side/bindings/c/sdk.h>
#include <launchdarkly/server_side/bindings/c/sdk.h>

#include <launchdarkly/client_side/bindings/c/config/builder.h>
#include <launchdarkly/server_side/bindings/c/config/builder.h>

#include <launchdarkly/bindings/c/context_builder.h>

int main() {
LDContextBuilder context_builder = LDContextBuilder_New();
LDContextBuilder_AddKind(context_builder, "user", "example-user-key");
LDContextBuilder_Attributes_SetName(context_builder, "user", "Sandy");
LDContext context = LDContextBuilder_Build(context_builder);

LDClientConfigBuilder client_config_builder =
LDClientConfigBuilder_New("foo");
LDClientConfig client_config = NULL;

LDStatus client_config_status =
LDClientConfigBuilder_Build(client_config_builder, &client_config);

if (LDStatus_Ok(client_config_status)) {
LDClientSDK client_sdk = LDClientSDK_New(client_config, context);
LDClientSDK_Free(client_sdk);
}

LDServerConfigBuilder server_config_builder =
LDServerConfigBuilder_New("foo");
LDServerConfig server_config = NULL;

LDStatus server_config_status =
LDServerConfigBuilder_Build(server_config_builder, &server_config);

if (LDStatus_Ok(server_config_status)) {
LDServerSDK server_sdk = LDServerSDK_New(server_config);
LDServerSDK_Free(server_sdk);
}

return 0;
}
4 changes: 2 additions & 2 deletions examples/hello-c-client/main.c
Original file line number Diff line number Diff line change
@@ -29,7 +29,7 @@ int main() {
LDClientConfigBuilder config_builder =
LDClientConfigBuilder_New(MOBILE_KEY);

LDClientConfig config;
LDClientConfig config = NULL;
LDStatus config_status =
LDClientConfigBuilder_Build(config_builder, &config);
if (!LDStatus_Ok(config_status)) {
@@ -44,7 +44,7 @@ int main() {

LDClientSDK client = LDClientSDK_New(config, context);

bool initialized_successfully;
bool initialized_successfully = false;
if (LDClientSDK_Start(client, INIT_TIMEOUT_MILLISECONDS,
&initialized_successfully)) {
if (initialized_successfully) {
15 changes: 15 additions & 0 deletions examples/hello-c-server/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Required for Apple Silicon support.
cmake_minimum_required(VERSION 3.19)

project(
LaunchDarklyHelloCServer
VERSION 0.1
DESCRIPTION "LaunchDarkly Hello C Server-side SDK"
LANGUAGES C
)

set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)

add_executable(hello-c-server main.c)
target_link_libraries(hello-c-server PRIVATE launchdarkly::server launchdarkly::sse launchdarkly::common Threads::Threads)
78 changes: 78 additions & 0 deletions examples/hello-c-server/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#include <launchdarkly/server_side/bindings/c/config/builder.h>
#include <launchdarkly/server_side/bindings/c/sdk.h>

#include <launchdarkly/bindings/c/context_builder.h>

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// Set SDK_KEY to your LaunchDarkly SKD key.
#define SDK_KEY ""

// Set FEATURE_FLAG_KEY to the feature flag key you want to evaluate.
#define FEATURE_FLAG_KEY "my-boolean-flag"

// Set INIT_TIMEOUT_MILLISECONDS to the amount of time you will wait for
// the client to become initialized.
#define INIT_TIMEOUT_MILLISECONDS 3000

int main() {
if (!strlen(SDK_KEY)) {
printf(
"*** Please edit main.c to set SDK_KEY to your LaunchDarkly "
"SDK key first\n\n");
return 1;
}

LDServerConfigBuilder config_builder = LDServerConfigBuilder_New(SDK_KEY);

LDServerConfig config = NULL;
LDStatus config_status =
LDServerConfigBuilder_Build(config_builder, &config);
if (!LDStatus_Ok(config_status)) {
printf("error: config is invalid: %s", LDStatus_Error(config_status));
return 1;
}

LDServerSDK client = LDServerSDK_New(config);

bool initialized_successfully = false;
if (LDServerSDK_Start(client, INIT_TIMEOUT_MILLISECONDS,
&initialized_successfully)) {
if (initialized_successfully) {
printf("*** SDK successfully initialized!\n\n");
} else {
printf("*** SDK failed to initialize\n");
return 1;
}
} else {
printf("SDK initialization didn't complete in %dms\n",
INIT_TIMEOUT_MILLISECONDS);
return 1;
}

LDContextBuilder context_builder = LDContextBuilder_New();
LDContextBuilder_AddKind(context_builder, "user", "example-user-key");
LDContextBuilder_Attributes_SetName(context_builder, "user", "Sandy");
LDContext context = LDContextBuilder_Build(context_builder);

bool flag_value =
LDServerSDK_BoolVariation(client, context, FEATURE_FLAG_KEY, false);

printf("*** Feature flag '%s' is %s for this user\n\n", FEATURE_FLAG_KEY,
flag_value ? "true" : "false");

// Here we ensure that the SDK shuts down cleanly and has a chance to
// deliver analytics events to LaunchDarkly before the program exits. If
// analytics events are not delivered, the user properties and flag usage
// statistics will not appear on your dashboard. In a normal long-running
// application, the SDK would continue running and events would be delivered
// automatically in the background.

LDContext_Free(context);
LDServerSDK_Free(client);

return 0;
}
12 changes: 6 additions & 6 deletions examples/hello-cpp-server/main.cpp
Original file line number Diff line number Diff line change
@@ -4,8 +4,8 @@
#include <cstring>
#include <iostream>

// Set MOBILE_KEY to your LaunchDarkly mobile key.
#define MOBILE_KEY ""
// Set SDK_KEY to your LaunchDarkly SDK key.
#define SDK_KEY ""

// Set FEATURE_FLAG_KEY to the feature flag key you want to evaluate.
#define FEATURE_FLAG_KEY "my-boolean-flag"
@@ -16,14 +16,14 @@

using namespace launchdarkly;
int main() {
if (!strlen(MOBILE_KEY)) {
if (!strlen(SDK_KEY)) {
printf(
"*** Please edit main.cpp to set MOBILE_KEY to your LaunchDarkly "
"mobile key first\n\n");
"*** Please edit main.cpp to set SDK_KEY to your LaunchDarkly "
"SDK key first\n\n");
return 1;
}

auto config = server_side::ConfigBuilder(MOBILE_KEY).Build();
auto config = server_side::ConfigBuilder(SDK_KEY).Build();
if (!config) {
std::cout << "error: config is invalid: " << config.error() << '\n';
return 1;
Original file line number Diff line number Diff line change
@@ -14,8 +14,8 @@ extern "C" { // only need to export C interface if
typedef struct _LDClientConfig* LDClientConfig;

/**
* Frees an unused configuration. Configurations passed into an LDClient must
* not be be freed.
* Free an unused configuration. Configurations used to construct an LDClientSDK
* must not be be freed.
*
* @param config Config to free.
*/
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@
#include <launchdarkly/bindings/c/flag_listener.h>
#include <launchdarkly/bindings/c/listener_connection.h>
#include <launchdarkly/bindings/c/memory_routines.h>
#include <launchdarkly/bindings/c/shared_function_argument_macro_definitions.h>
#include <launchdarkly/bindings/c/status.h>
#include <launchdarkly/bindings/c/value.h>

@@ -27,9 +28,6 @@ extern "C" { // only need to export C interface if

typedef struct _LDClientSDK* LDClientSDK;

#define LD_NONBLOCKING 0
#define LD_DISCARD_DETAIL NULL

/**
* Constructs a new client-side LaunchDarkly SDK from a configuration and
* context.
1 change: 0 additions & 1 deletion libs/client-sdk/src/bindings/c/sdk.cpp
Original file line number Diff line number Diff line change
@@ -203,7 +203,6 @@ LDClientSDK_StringVariation(LDClientSDK sdk,
LD_ASSERT_NOT_NULL(flag_key);
LD_ASSERT_NOT_NULL(default_value);

// TODO: custom allocation / free routines
return strdup(
TO_SDK(sdk)->StringVariation(flag_key, default_value).c_str());
}
2 changes: 1 addition & 1 deletion libs/client-sdk/tests/client_c_bindings_test.cpp
Original file line number Diff line number Diff line change
@@ -49,7 +49,7 @@ TEST(ClientBindings, RegisterFlagListener) {
ASSERT_TRUE(LDStatus_Ok(status));

LDContextBuilder ctx_builder = LDContextBuilder_New();
LDContextBuilder_AddKind(ctx_builder, "`user", "shadow");
LDContextBuilder_AddKind(ctx_builder, "user", "shadow");

LDContext context = LDContextBuilder_Build(ctx_builder);

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/** @file */
#pragma once

/* Function should operate asynchronously. */
#define LD_NONBLOCKING 0

/* Function should discard evaluation details. */
#define LD_DISCARD_DETAIL NULL
2 changes: 0 additions & 2 deletions libs/common/include/launchdarkly/config/client.hpp
Original file line number Diff line number Diff line change
@@ -15,9 +15,7 @@ using SDK = config::shared::ClientSDK;
using Defaults = config::shared::Defaults<SDK>;
using AppInfoBuilder = config::shared::builders::AppInfoBuilder;
using EndpointsBuilder = config::shared::builders::EndpointsBuilder<SDK>;

using ConfigBuilder = config::shared::builders::ConfigBuilder<SDK>;

using EventsBuilder = config::shared::builders::EventsBuilder<SDK>;
using HttpPropertiesBuilder =
config::shared::builders::HttpPropertiesBuilder<SDK>;
1 change: 1 addition & 0 deletions libs/common/include/launchdarkly/config/server.hpp
Original file line number Diff line number Diff line change
@@ -19,6 +19,7 @@ using EventsBuilder = config::shared::builders::EventsBuilder<SDK>;
using HttpPropertiesBuilder =
config::shared::builders::HttpPropertiesBuilder<SDK>;
using DataSourceBuilder = config::shared::builders::DataSourceBuilder<SDK>;
using LoggingBuilder = config::shared::builders::LoggingBuilder;
using PersistenceBuilder = config::shared::builders::PersistenceBuilder<SDK>;

using Config = config::Config<SDK>;
Loading