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

created this package which provides a dart interface #169

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
29 changes: 29 additions & 0 deletions clients/dart/dart_cac_client/.gitignore
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/
10 changes: 10 additions & 0 deletions clients/dart/dart_cac_client/.metadata
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
3 changes: 3 additions & 0 deletions clients/dart/dart_cac_client/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## 0.0.1

* TODO: Describe initial release.
1 change: 1 addition & 0 deletions clients/dart/dart_cac_client/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
TODO: Add your license here.
79 changes: 79 additions & 0 deletions clients/dart/dart_cac_client/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Dart CAC Client

This package provides a Dart interface for the CAC (Configuration as Code) client, allowing you to interact with the CAC server to retrieve and manage configurations.

## Table of Contents
- [Dart CAC Client](#dart-cac-client)
- [Table of Contents](#table-of-contents)
- [Installation](#installation)
- [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)

## Installation

Add the following dependency to your `pubspec.yaml` file:

```yaml
dependencies:
dart_cac_client:
git:
url: [email protected]:your_repo/dart_cac_client.git
```

## Usage

### Creating a Client
To create a new CAC client, instantiate the DartCacClient class with the tenant name, update frequency (in seconds), and host URL

```dart
final client = DartCacClient('dev', 60, 'http://localhost:8080');
```

### Starting Polling for Updates
Use the cacStartPolling method to start polling for configuration updates for the specified tenant:

```dart
client.cacStartPolling("<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();
```
4 changes: 4 additions & 0 deletions clients/dart/dart_cac_client/analysis_options.yaml
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
204 changes: 204 additions & 0 deletions clients/dart/dart_cac_client/lib/cac_client.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
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(path.current, '/../../../target/debug/', 'cac_client.dll');
}
if (Platform.isMacOS) {
return path.join(
path.current, '/../../../target/debug/', 'libcac_client.dylib');
}
return path.join(path.current, '/../../../target/debug/', 'libcac_client.so');
}

// Bind the C functions
final CacNewClientDart _cacNewClient = _lib
.lookup<ffi.NativeFunction<CacNewClientNative>>('cac_new_client')
.asFunction();

final CacGetClientDart _cacGetClient = _lib
.lookup<ffi.NativeFunction<CacGetClientNative>>('cac_get_client')
.asFunction();

final CacFreeClientDart _cacFreeClient = _lib
.lookup<ffi.NativeFunction<CacFreeClientNative>>('cac_free_client')
.asFunction();

final CacGetConfigDart _cacGetConfig = _lib
.lookup<ffi.NativeFunction<CacGetConfigNative>>('cac_get_config')
.asFunction();

final CacGetDefaultConfigDart _cacGetDefaultConfigs = _lib
.lookup<ffi.NativeFunction<CacGetDefaultConfigNative>>(
'cac_get_default_config')
.asFunction();

final CacGetLastModifiedDart _cacGetLastModified = _lib
.lookup<ffi.NativeFunction<CacGetLastModifiedNative>>(
'cac_get_last_modified')
.asFunction();

final CacFreeStringDart _cacFreeString = _lib
.lookup<ffi.NativeFunction<CacFreeStringNative>>('cac_free_string')
.asFunction();

final CacLastErrorMessageDart _cacLastErrorMessage = _lib
.lookup<ffi.NativeFunction<CacLastErrorMessageNative>>(
'cac_last_error_message')
.asFunction();

final CacGetResolvedConfigsDart _cacGetResolvedConfigs = _lib
.lookup<ffi.NativeFunction<CacGetResolvedConfigsNative>>(
'cac_get_resolved_config')
.asFunction();

final CacStartPollingUpdateDart _cacStartPollingUpdate = _lib
.lookup<ffi.NativeFunction<CacStartPollingUpdateNative>>(
'cac_start_polling_update')
.asFunction();

// Dart wrapper class
class CacClient {
late ffi.Pointer<ffi.Void> _clientPtr;

CacClient(String tenant, int updateFrequency, String hostname) {
final tenantPtr = tenant.toNativeUtf8();
final hostnamePtr = hostname.toNativeUtf8();

final result = _cacNewClient(tenantPtr, updateFrequency, hostnamePtr);
print("cac_new_client result: $result");

malloc.free(tenantPtr);
malloc.free(hostnamePtr);

if (result != 0) {
final errorPtr = _cacLastErrorMessage();
final errorMessage = errorPtr.toDartString();
print("Error message: $errorMessage");
_cacFreeString(errorPtr);
throw Exception("Failed to create CAC client: $errorMessage");
}

_clientPtr = _cacGetClient(tenant.toNativeUtf8());
if (_clientPtr == ffi.nullptr) {
final errorPtr = _cacLastErrorMessage();
final errorMessage = errorPtr.toDartString();
print("Error getting client pointer: $errorMessage");
_cacFreeString(errorPtr);
throw Exception("Failed to get CAC client: $errorMessage");
}

print("Client pointer obtained successfully");
}

String getConfig(String filterQuery, String filterPrefix) {
print(
"Attempting to get config with filterQuery: $filterQuery, filterPrefix: $filterPrefix");

final filterQueryPtr = filterQuery.toNativeUtf8();
final filterPrefixPtr = filterPrefix.toNativeUtf8();

final configPtr =
_cacGetConfig(_clientPtr, filterQueryPtr, filterPrefixPtr);

malloc.free(filterQueryPtr);
malloc.free(filterPrefixPtr);

if (configPtr == ffi.nullptr) {
final errorPtr = _cacLastErrorMessage();
final errorMessage = errorPtr.toDartString();
print("Error getting config: $errorMessage");
_cacFreeString(errorPtr);
throw Exception("Failed to get config: $errorMessage");
}

print("Config pointer received, converting to Dart string");
final config = configPtr.toDartString();
print("Received config: $config");
_cacFreeString(configPtr);

return config;
}

String getDefaultConfigs(String filterKeys) {
final filterKeysPtr = filterKeys.toNativeUtf8();

final configPtr = _cacGetDefaultConfigs(_clientPtr, filterKeysPtr);

malloc.free(filterKeysPtr);

if (configPtr == ffi.nullptr) {
final errorPtr = _cacLastErrorMessage();
final errorMessage = errorPtr.toDartString();
print("Error getting config: $errorMessage");
_cacFreeString(errorPtr);
throw Exception("Failed to get config: $errorMessage");
}

final config = configPtr.toDartString();
print("Received Default config: $config");
_cacFreeString(configPtr);

return config;
}

String getLastModified() {
if (_clientPtr == ffi.nullptr) {
throw Exception("Failed to get CAC client!");
}
var lastModified = _cacGetLastModified(_clientPtr);
return lastModified.toDartString();
}

String getResolvedConfigs(
String query, String filterKeys, String mergeStrategy) {
if (_clientPtr == ffi.nullptr) {
throw Exception("Failed to get CAC client!");
}

final queryPtr = query.toNativeUtf8();
final filterKeysPtr = filterKeys.toNativeUtf8();
final mergeStrategyPtr = mergeStrategy.toNativeUtf8();

final resolvedConfigPtr = _cacGetResolvedConfigs(
_clientPtr, queryPtr, filterKeysPtr, mergeStrategyPtr);

malloc.free(queryPtr);
malloc.free(filterKeysPtr);
malloc.free(mergeStrategyPtr);

if (resolvedConfigPtr == ffi.nullptr) {
final errorPtr = _cacLastErrorMessage();
final errorMessage = errorPtr.toDartString();
print("Error getting config: $errorMessage");
_cacFreeString(errorPtr);
throw Exception("Failed to get config: $errorMessage");
}

return resolvedConfigPtr.toDartString();
}

void startPollingUpdate(String tenant) {
if (_clientPtr == ffi.nullptr) {
throw Exception("Failed to get CAC client!");
}
final tenantPtr = tenant.toNativeUtf8();
_cacStartPollingUpdate(tenantPtr);
return;
}

void dispose() {
if (_clientPtr != ffi.nullptr) {
_cacFreeClient(_clientPtr);
_clientPtr = ffi.nullptr;
}
}
}
Loading
Loading