-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
e3ebed6
commit 557a098
Showing
11 changed files
with
311 additions
and
46 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
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
117 changes: 117 additions & 0 deletions
117
src/CatConsult.AppConfigConfigurationProvider/AppConfigConfigurationProvider.cs
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,117 @@ | ||
using Amazon.AppConfigData; | ||
using Amazon.AppConfigData.Model; | ||
|
||
using CatConsult.ConfigurationParsers; | ||
|
||
using Microsoft.Extensions.Configuration; | ||
using Microsoft.Extensions.Primitives; | ||
|
||
namespace CatConsult.AppConfigConfigurationProvider; | ||
|
||
public sealed class AppConfigConfigurationProvider : ConfigurationProvider, IDisposable | ||
{ | ||
private const int LockReleaseTimeout = 3_000; | ||
|
||
private readonly IAmazonAppConfigData _client; | ||
private readonly AppConfigProfile _profile; | ||
private readonly SemaphoreSlim _lock; | ||
|
||
private IDisposable? _reloadChangeToken; | ||
|
||
public AppConfigConfigurationProvider(IAmazonAppConfigData client, AppConfigProfile profile) | ||
{ | ||
_profile = profile; | ||
_client = client; | ||
_lock = new SemaphoreSlim(1, 1); | ||
} | ||
|
||
public AppConfigConfigurationProvider(AppConfigProfile profile) : this(new AmazonAppConfigDataClient(), profile) { } | ||
|
||
private string? ConfigurationToken { get; set; } | ||
|
||
private DateTimeOffset NextPollingTime { get; set; } | ||
|
||
public override void Load() | ||
{ | ||
LoadAsync().GetAwaiter().GetResult(); | ||
|
||
if (_profile.ReloadAfter.HasValue) | ||
{ | ||
_reloadChangeToken = ChangeToken.OnChange( | ||
() => new CancellationChangeToken( | ||
new CancellationTokenSource(_profile.ReloadAfter.Value).Token | ||
), | ||
Load | ||
); | ||
} | ||
} | ||
|
||
private async Task LoadAsync() | ||
{ | ||
if (!await _lock.WaitAsync(LockReleaseTimeout)) | ||
{ | ||
return; | ||
} | ||
|
||
try | ||
{ | ||
if (DateTimeOffset.UtcNow < NextPollingTime) | ||
{ | ||
return; | ||
} | ||
|
||
if (string.IsNullOrEmpty(ConfigurationToken)) | ||
{ | ||
await InitializeAppConfigSessionAsync(); | ||
} | ||
|
||
var request = new GetLatestConfigurationRequest | ||
{ | ||
ConfigurationToken = ConfigurationToken | ||
}; | ||
|
||
var response = await _client.GetLatestConfigurationAsync(request); | ||
ConfigurationToken = response.NextPollConfigurationToken; | ||
NextPollingTime = DateTimeOffset.UtcNow.AddSeconds(response.NextPollIntervalInSeconds); | ||
|
||
// If the remote configuration has changed, the API will send back data and we re-parse | ||
if (response.ContentLength > 0) | ||
{ | ||
Data = ParseConfig(response.Configuration, response.ContentType); | ||
} | ||
} | ||
finally | ||
{ | ||
_lock.Release(); | ||
} | ||
} | ||
|
||
private async Task InitializeAppConfigSessionAsync() | ||
{ | ||
var session = await _client.StartConfigurationSessionAsync(new StartConfigurationSessionRequest | ||
{ | ||
ApplicationIdentifier = _profile.ApplicationId, | ||
EnvironmentIdentifier = _profile.EnvironmentId, | ||
ConfigurationProfileIdentifier = _profile.ProfileId, | ||
}); | ||
|
||
ConfigurationToken = session.InitialConfigurationToken; | ||
} | ||
|
||
private static IDictionary<string, string?> ParseConfig(Stream stream, string? contentType) | ||
{ | ||
if (!string.IsNullOrEmpty(contentType)) | ||
{ | ||
contentType = contentType.Split(";")[0]; | ||
} | ||
|
||
return contentType switch | ||
{ | ||
"application/json" => JsonConfigurationParser.Parse(stream), | ||
"application/x-yaml" => YamlConfigurationParser.Parse(stream), | ||
_ => throw new FormatException($"This configuration provider does not support: {contentType ?? "Unknown"}") | ||
}; | ||
} | ||
|
||
public void Dispose() => _reloadChangeToken?.Dispose(); | ||
} |
44 changes: 29 additions & 15 deletions
44
src/CatConsult.AppConfigConfigurationProvider/AppConfigConfigurationProviderExtensions.cs
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 |
---|---|---|
@@ -1,37 +1,51 @@ | ||
using Amazon.AppConfigData; | ||
|
||
using CatConsult.AppConfigConfigurationProvider.Utilities; | ||
|
||
using Microsoft.Extensions.Configuration; | ||
|
||
namespace CatConsult.AppConfigConfigurationProvider; | ||
|
||
// ReSharper disable UnusedType.Global | ||
// ReSharper disable UnusedMember.Global | ||
// ReSharper disable MemberCanBePrivate.Global | ||
public static class AppConfigConfigurationProviderExtensions | ||
{ | ||
public const string DefaultSectionName = "AppConfig"; | ||
|
||
public static IConfigurationBuilder AddAppConfig( | ||
this IConfigurationBuilder builder, | ||
string sectionName = "AppConfig" | ||
string sectionName = DefaultSectionName | ||
) | ||
{ | ||
var options = builder.Build() | ||
.GetSection(sectionName) | ||
.Get<AppConfigOptions>(); | ||
|
||
if (options is null) | ||
foreach (var profile in LoadProfiles(builder, sectionName)) | ||
{ | ||
return builder; | ||
builder.Add(new AppConfigConfigurationSource(profile)); | ||
} | ||
|
||
var profiles = options.Profiles.Select(AppConfigProfileParser.Parse); | ||
return builder; | ||
} | ||
|
||
foreach (var profile in profiles) | ||
public static IConfigurationBuilder AddAppConfig( | ||
this IConfigurationBuilder builder, | ||
IAmazonAppConfigData client, | ||
string sectionName = DefaultSectionName | ||
) | ||
{ | ||
foreach (var profile in LoadProfiles(builder, sectionName)) | ||
{ | ||
builder.AddAppConfig( | ||
profile.ApplicationId, | ||
profile.EnvironmentId, | ||
profile.ProfileId, | ||
TimeSpan.FromSeconds(profile.ReloadAfter ?? options.Defaults.ReloadAfter) | ||
); | ||
builder.Add(new AppConfigConfigurationSource(client, profile)); | ||
} | ||
|
||
return builder; | ||
} | ||
|
||
private static IEnumerable<AppConfigProfile> LoadProfiles(IConfigurationBuilder builder, string sectionName) | ||
{ | ||
var options = builder.Build() | ||
.GetSection(sectionName) | ||
.Get<AppConfigOptions>() ?? new AppConfigOptions(); | ||
|
||
return options.Profiles.Select(AppConfigProfileParser.Parse); | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
src/CatConsult.AppConfigConfigurationProvider/AppConfigConfigurationSource.cs
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,18 @@ | ||
using Amazon.AppConfigData; | ||
|
||
using Microsoft.Extensions.Configuration; | ||
|
||
namespace CatConsult.AppConfigConfigurationProvider; | ||
|
||
public sealed class AppConfigConfigurationSource : IConfigurationSource | ||
{ | ||
private readonly AppConfigConfigurationProvider _provider; | ||
|
||
public AppConfigConfigurationSource(IAmazonAppConfigData client, AppConfigProfile profile) => | ||
_provider = new AppConfigConfigurationProvider(client, profile); | ||
|
||
public AppConfigConfigurationSource(AppConfigProfile profile) => | ||
_provider = new AppConfigConfigurationProvider(profile); | ||
|
||
public IConfigurationProvider Build(IConfigurationBuilder builder) => _provider; | ||
} |
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
10 changes: 0 additions & 10 deletions
10
...ult.AppConfigConfigurationProvider/Extensions/AppConfigConfigurationProviderExtensions.cs
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.