-
Notifications
You must be signed in to change notification settings - Fork 30
/
Copy pathConfigCatProvider.cs
109 lines (97 loc) · 5.1 KB
/
ConfigCatProvider.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
using System;
using System.Threading;
using System.Threading.Tasks;
using ConfigCat.Client;
using ConfigCat.Client.Configuration;
using OpenFeature.Constant;
using OpenFeature.Error;
using OpenFeature.Model;
namespace OpenFeature.Contrib.ConfigCat
{
/// <summary>
/// ConfigCatProvider is the .NET provider implementation for the feature flag solution ConfigCat.
/// </summary>
public sealed class ConfigCatProvider : FeatureProvider
{
private const string Name = "ConfigCat Provider";
internal readonly IConfigCatClient Client;
/// <summary>
/// Creates new instance of <see cref="ConfigCatProvider"/>
/// </summary>
/// <param name="sdkKey">SDK Key to access the ConfigCat config.</param>
/// <param name="configBuilder">The action used to configure the client.</param>
/// <exception cref="ArgumentNullException"><paramref name="sdkKey"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentException"><paramref name="sdkKey"/> is an empty string or in an invalid format.</exception>
public ConfigCatProvider(string sdkKey, Action<ConfigCatClientOptions> configBuilder = null)
{
Client = ConfigCatClient.Get(sdkKey, configBuilder);
}
/// <inheritdoc/>
public override Metadata GetMetadata()
{
return new Metadata(Name);
}
/// <inheritdoc/>
public override Task<ResolutionDetails<bool>> ResolveBooleanValueAsync(string flagKey, bool defaultValue, EvaluationContext context = null, CancellationToken cancellationToken = default)
{
return ResolveFlag(flagKey, context, defaultValue, cancellationToken);
}
/// <inheritdoc/>
public override Task<ResolutionDetails<string>> ResolveStringValueAsync(string flagKey, string defaultValue, EvaluationContext context = null, CancellationToken cancellationToken = default)
{
return ResolveFlag(flagKey, context, defaultValue, cancellationToken);
}
/// <inheritdoc/>
public override Task<ResolutionDetails<int>> ResolveIntegerValueAsync(string flagKey, int defaultValue, EvaluationContext context = null, CancellationToken cancellationToken = default)
{
return ResolveFlag(flagKey, context, defaultValue, cancellationToken);
}
/// <inheritdoc/>
public override Task<ResolutionDetails<double>> ResolveDoubleValueAsync(string flagKey, double defaultValue, EvaluationContext context = null, CancellationToken cancellationToken = default)
{
return ResolveFlag(flagKey, context, defaultValue, cancellationToken);
}
/// <inheritdoc/>
public override async Task<ResolutionDetails<Value>> ResolveStructureValueAsync(string flagKey, Value defaultValue, EvaluationContext context = null, CancellationToken cancellationToken = default)
{
var user = context?.BuildUser();
var result = await Client.GetValueDetailsAsync(flagKey, defaultValue?.AsObject, user, cancellationToken);
var returnValue = result.IsDefaultValue ? defaultValue : new Value(result.Value);
var details = new ResolutionDetails<Value>(flagKey, returnValue, TranslateErrorCode(result.ErrorCode), errorMessage: result.ErrorMessage, variant: result.VariationId);
if (details.ErrorType == ErrorType.None)
{
return details;
}
throw new FeatureProviderException(details.ErrorType, details.ErrorMessage);
}
private async Task<ResolutionDetails<T>> ResolveFlag<T>(string flagKey, EvaluationContext context, T defaultValue, CancellationToken cancellationToken)
{
var user = context?.BuildUser();
var result = await Client.GetValueDetailsAsync(flagKey, defaultValue, user, cancellationToken);
var details = new ResolutionDetails<T>(flagKey, result.Value, TranslateErrorCode(result.ErrorCode), errorMessage: result.ErrorMessage, variant: result.VariationId);
if (details.ErrorType == ErrorType.None)
{
return details;
}
throw new FeatureProviderException(details.ErrorType, details.ErrorMessage);
}
private static ErrorType TranslateErrorCode(EvaluationErrorCode errorCode)
{
switch (errorCode)
{
case EvaluationErrorCode.None:
return ErrorType.None;
case EvaluationErrorCode.InvalidConfigModel:
return ErrorType.ParseError;
case EvaluationErrorCode.SettingValueTypeMismatch:
return ErrorType.TypeMismatch;
case EvaluationErrorCode.ConfigJsonNotAvailable:
return ErrorType.ProviderNotReady;
case EvaluationErrorCode.SettingKeyMissing:
return ErrorType.FlagNotFound;
default:
return ErrorType.General;
}
}
}
}