-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
added client for experimentation system
- Loading branch information
1 parent
0fa5e0b
commit 26f5c0d
Showing
12 changed files
with
584 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# Miscellaneous | ||
*.class | ||
*.log | ||
*.pyc | ||
*.swp | ||
.DS_Store | ||
.atom/ | ||
.buildlog/ | ||
.history | ||
.svn/ | ||
migrate_working_dir/ | ||
|
||
# IntelliJ related | ||
*.iml | ||
*.ipr | ||
*.iws | ||
.idea/ | ||
|
||
# The .vscode folder contains launch configuration and tasks you configure in | ||
# VS Code which you may wish to be included in version control, so this line | ||
# is commented out by default. | ||
#.vscode/ | ||
|
||
# Flutter/Dart/Pub related | ||
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. | ||
/pubspec.lock | ||
**/doc/api/ | ||
.dart_tool/ | ||
build/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# This file tracks properties of this Flutter project. | ||
# Used by Flutter tool to assess capabilities and perform upgrades etc. | ||
# | ||
# This file should be version controlled and should not be manually edited. | ||
|
||
version: | ||
revision: "ba393198430278b6595976de84fe170f553cc728" | ||
channel: "stable" | ||
|
||
project_type: package |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
## 0.0.1 | ||
|
||
* TODO: Describe initial release. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
TODO: Add your license here. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
# Dart Experimentation Client | ||
|
||
This package provides a Dart interface for the Experimentation client, allowing you to interact with the experimentation server to retrieve and manage experiments. | ||
|
||
## Table of Contents | ||
- [Dart Experimentation Client](#dart-experimentation-client) | ||
- [Table of Contents](#table-of-contents) | ||
- [Usage](#usage) | ||
- [Creating a Client](#creating-a-client) | ||
- [Starting Polling for Updates](#starting-polling-for-updates) | ||
- [Retrieving Configurations](#retrieving-configurations) | ||
- [Getting Default Configurations](#getting-default-configurations) | ||
- [Getting Resolved Configurations](#getting-resolved-configurations) | ||
- [Getting Last Modified Timestamp](#getting-last-modified-timestamp) | ||
- [Disposing the Client](#disposing-the-client) | ||
|
||
## Usage | ||
|
||
### Creating a Client | ||
To create a new DartExptClient client, instantiate the DartCacClient class with the tenant name, update frequency (in seconds), and host URL | ||
|
||
```dart | ||
final client = To create a new DartExptClient client, instantiate the DartCacClient class with the tenant name, update frequency (in seconds), and host URL | ||
('dev', 60, 'http://localhost:8080'); | ||
``` | ||
|
||
### Starting Polling for Updates | ||
Use the exptStartPolling method to start polling for configuration updates for the specified tenant: | ||
|
||
```dart | ||
client.exptStartPolling("<tenant name>"); | ||
``` | ||
|
||
### Retrieving Configurations | ||
Use the getConfigs method to retrieve configurations based on a filter query and filter prefix: | ||
```dart | ||
String configs = client.getConfigs('{"country": "India"}', 'country'); | ||
``` | ||
|
||
### Getting Default Configurations | ||
Use the getDefaultConfig method to retrieve the default configurations for the specified keys: | ||
|
||
```dart | ||
String defaultConfigs = client.getDefaultConfig("india"); | ||
``` | ||
|
||
### Getting Resolved Configurations | ||
Use the getResolvedConfig method to retrieve resolved configurations based on the provided query, keys, and merge strategy: | ||
|
||
|
||
```dart | ||
String resolvedConfigs = client.getResolvedConfig( | ||
'{"query": "example"}', "key1, key2", MergeStrategy.MERGE/MergeStrategy.REPLACE); | ||
``` | ||
|
||
|
||
### Getting Last Modified Timestamp | ||
Use the getCacLastModified method to get the last modified timestamp of the configurations: | ||
|
||
```dart | ||
String lastModified = client.getCacLastModified(); | ||
``` | ||
|
||
### Disposing the Client | ||
Ensure that you dispose of the client properly to free up resources: | ||
```dart | ||
client.dispose(); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
include: package:flutter_lints/flutter.yaml | ||
|
||
# Additional information about this file can be found at | ||
# https://dart.dev/guides/language/analysis-options |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,223 @@ | ||
import 'dart:ffi' as ffi; | ||
import 'package:dart_cac_client/types/types.dart'; | ||
import 'package:ffi/ffi.dart'; | ||
import 'dart:io' show Platform; | ||
import 'package:path/path.dart' as path; | ||
|
||
// Define the library | ||
final ffi.DynamicLibrary _lib = ffi.DynamicLibrary.open(_libName); | ||
|
||
// Helper to get the correct library name based on the platform | ||
String get _libName { | ||
if (Platform.isWindows) { | ||
return path.join( | ||
'/Users/subhash/working-repos/github/superposition/target/debug/', | ||
'libexperimentation_client.dll'); | ||
} | ||
if (Platform.isMacOS) { | ||
return path.join( | ||
'/Users/subhash/working-repos/github/superposition/target/debug/', | ||
'libexperimentation_client.dylib'); | ||
} | ||
return path.join( | ||
'/Users/subhash/working-repos/github/superposition/target/debug/', | ||
'libexperimentation_client.so'); | ||
} | ||
|
||
// Bind the C functions | ||
final ExptNewClientDart _exptNewClient = _lib | ||
.lookup<ffi.NativeFunction<ExptNewClientNative>>('expt_new_client') | ||
.asFunction(); | ||
|
||
final ExptGetClientDart _exptGetClient = _lib | ||
.lookup<ffi.NativeFunction<ExptGetClientNative>>('expt_get_client') | ||
.asFunction(); | ||
|
||
final ExptLastErrorLengthDart _exptLastErrorLength = _lib | ||
.lookup<ffi.NativeFunction<ExptLastErrorLengthNative>>( | ||
'expt_last_error_length') | ||
.asFunction(); | ||
|
||
final ExptLastErrorMessageDart _exptLastErrorMessage = _lib | ||
.lookup<ffi.NativeFunction<ExptLastErrorMessageNative>>( | ||
'expt_last_error_message') | ||
.asFunction(); | ||
|
||
final ExptFreeStringDart _exptFreeString = _lib | ||
.lookup<ffi.NativeFunction<ExptFreeStringNative>>('expt_free_string') | ||
.asFunction(); | ||
|
||
final ExpStartPollingUpdateDart _exptStartPollingUpdate = _lib | ||
.lookup<ffi.NativeFunction<ExpStartPollingUpdateNative>>( | ||
'expt_start_polling_update') | ||
.asFunction(); | ||
|
||
final ExptFreeClientDart _exptFreeClient = _lib | ||
.lookup<ffi.NativeFunction<ExptFreeClientNative>>('expt_free_client') | ||
.asFunction(); | ||
|
||
final ExptGetApplicableVariantDart _exptGetApplicableVariant = _lib | ||
.lookup<ffi.NativeFunction<ExptGetApplicableVariantNative>>( | ||
'expt_get_applicable_variant') | ||
.asFunction(); | ||
|
||
final ExptGetSatisfiedExperimentsDart _exptGetSatisfiedExperiments = _lib | ||
.lookup<ffi.NativeFunction<ExptGetSatisfiedExperimentsNative>>( | ||
'expt_get_satisfied_experiments') | ||
.asFunction(); | ||
|
||
final ExptGetFilteredSatisfiedExperimentsDart | ||
_exptGetFilteredSatisfiedExperiments = _lib | ||
.lookup<ffi.NativeFunction<ExptGetFilteredSatisfiedExperimentsNative>>( | ||
'expt_get_filtered_satisfied_experiments') | ||
.asFunction(); | ||
|
||
final ExptGetRunningExperimentsDart _exptGetRunningExperiments = _lib | ||
.lookup<ffi.NativeFunction<ExptGetRunningExperimentsNative>>( | ||
'expt_get_running_experiments') | ||
.asFunction(); | ||
|
||
// Dart wrapper class | ||
class ExptClient { | ||
late ffi.Pointer<ffi.Void> _clientPtr; | ||
|
||
ExptClient(String tenant, int updateFrequency, String hostname) { | ||
final tenantPtr = tenant.toNativeUtf8(); | ||
final hostnamePtr = hostname.toNativeUtf8(); | ||
|
||
final result = _exptNewClient(tenantPtr, updateFrequency, hostnamePtr); | ||
print("Expt Client result: $result"); | ||
|
||
_exptFreeString(tenantPtr); | ||
_exptFreeString(hostnamePtr); | ||
|
||
if (result != 0) { | ||
final errorPtr = _exptLastErrorMessage(); | ||
final errorMessage = errorPtr.toDartString(); | ||
print("Error message: $errorMessage"); | ||
_exptFreeString(errorPtr); | ||
throw Exception("Failed to create Experimentation client: $errorMessage"); | ||
} | ||
|
||
_clientPtr = _exptGetClient(tenant.toNativeUtf8()); | ||
if (_clientPtr == ffi.nullptr) { | ||
final errorPtr = _exptLastErrorMessage(); | ||
final errorMessage = errorPtr.toDartString(); | ||
print("Error getting client pointer: $errorMessage"); | ||
_exptFreeString(errorPtr); | ||
throw Exception("Failed to get Experimentation client: $errorMessage"); | ||
} | ||
print("Client pointer obtained successfully"); | ||
} | ||
|
||
String getApplicableVariants(String context, int toss) { | ||
final clientPtr = context.toNativeUtf8(); | ||
final tossPtr = malloc.allocate<ffi.Int16>(ffi.sizeOf<ffi.Int16>()); | ||
tossPtr.value = toss; | ||
final applicableVariantPtr = | ||
_exptGetApplicableVariant(_clientPtr, clientPtr, tossPtr); | ||
|
||
_exptFreeString(clientPtr); | ||
malloc.free(tossPtr); | ||
|
||
if (applicableVariantPtr == ffi.nullptr) { | ||
final errorPtr = _exptLastErrorMessage(); | ||
final errorMessage = errorPtr.toDartString(); | ||
print("Error getting Applicable Variant: $errorMessage"); | ||
_exptFreeString(errorPtr); | ||
throw Exception("Failed to get config: $errorMessage"); | ||
} | ||
final applicableVariant = applicableVariantPtr.toDartString(); | ||
print("Received Applicable Variant: $applicableVariant"); | ||
_exptFreeString(applicableVariantPtr); | ||
|
||
return applicableVariant; | ||
} | ||
|
||
String getSatisfiedExperiments(String context, String filterPrefix) { | ||
final contextPtr = context.toNativeUtf8(); | ||
final filterPrefixPtr = filterPrefix.toNativeUtf8(); | ||
|
||
final satisfiedExperimentsPtr = | ||
_exptGetSatisfiedExperiments(_clientPtr, contextPtr, filterPrefixPtr); | ||
|
||
_exptFreeString(contextPtr); | ||
_exptFreeString(filterPrefixPtr); | ||
|
||
if (satisfiedExperimentsPtr == ffi.nullptr) { | ||
final errorPtr = _exptLastErrorMessage(); | ||
final errorMessage = errorPtr.toDartString(); | ||
print("Error getting satisfied experiments: $errorMessage"); | ||
_exptFreeString(errorPtr); | ||
throw Exception("Failed to get satisfied experiments: $errorMessage"); | ||
} | ||
|
||
final satisfiedExperiments = satisfiedExperimentsPtr.toDartString(); | ||
print("Received satisfied experiments: $satisfiedExperiments"); | ||
_exptFreeString(satisfiedExperimentsPtr); | ||
|
||
return satisfiedExperiments; | ||
} | ||
|
||
String getFilteredSatisfiedExperiments(String context, String filterPrefix) { | ||
if (_clientPtr == ffi.nullptr) { | ||
throw Exception("Failed to get Experimentation client!"); | ||
} | ||
final contextPtr = context.toNativeUtf8(); | ||
final filterPrefixPtr = filterPrefix.toNativeUtf8(); | ||
|
||
final fltSatisfiedExperimentsPtr = _exptGetFilteredSatisfiedExperiments( | ||
_clientPtr, contextPtr, filterPrefixPtr); | ||
|
||
_exptFreeString(contextPtr); | ||
_exptFreeString(filterPrefixPtr); | ||
|
||
if (fltSatisfiedExperimentsPtr == ffi.nullptr) { | ||
final errorPtr = _exptLastErrorMessage(); | ||
final errorMessage = errorPtr.toDartString(); | ||
print("Error getting filtered satisfied experiments : $errorMessage"); | ||
_exptFreeString(errorPtr); | ||
throw Exception( | ||
"Failed to get filtered satisfied experiments: $errorMessage"); | ||
} | ||
var fltSatisfiedExperiments = fltSatisfiedExperimentsPtr.toDartString(); | ||
_exptFreeString(fltSatisfiedExperimentsPtr); | ||
|
||
return fltSatisfiedExperiments; | ||
} | ||
|
||
String getRunningExperiments() { | ||
if (_clientPtr == ffi.nullptr) { | ||
throw Exception("Failed to get Experimentation client!"); | ||
} | ||
final runningExprsPtr = _exptGetRunningExperiments(_clientPtr); | ||
if (runningExprsPtr == ffi.nullptr) { | ||
final errorPtr = _exptLastErrorMessage(); | ||
final errorMessage = errorPtr.toDartString(); | ||
print("Error getting filtered running experiments : $errorMessage"); | ||
_exptFreeString(errorPtr); | ||
throw Exception( | ||
"Failed to get filtered running experiments: $errorMessage"); | ||
} | ||
var runningExprs = runningExprsPtr.toDartString(); | ||
_exptFreeString(runningExprsPtr); | ||
return runningExprs; | ||
} | ||
|
||
void startPollingUpdate(String tenant) { | ||
if (_clientPtr == ffi.nullptr) { | ||
throw Exception("Failed to get Experimentation client!"); | ||
} | ||
final tenantPtr = tenant.toNativeUtf8(); | ||
_exptStartPollingUpdate(tenantPtr); | ||
_exptFreeString(tenantPtr); | ||
print("finish polling"); | ||
} | ||
|
||
void dispose() { | ||
if (_clientPtr != ffi.nullptr) { | ||
_exptFreeClient(_clientPtr); | ||
_clientPtr = ffi.nullptr; | ||
} | ||
} | ||
} |
Oops, something went wrong.