Skip to content

Commit

Permalink
Add ConfigFetched hook
Browse files Browse the repository at this point in the history
  • Loading branch information
adams85 committed Apr 16, 2024
1 parent acc00da commit 7fcf0bb
Show file tree
Hide file tree
Showing 9 changed files with 94 additions and 22 deletions.
7 changes: 7 additions & 0 deletions src/ConfigCatClient/ConfigCatClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -744,6 +744,13 @@ public event EventHandler<FlagEvaluatedEventArgs>? FlagEvaluated
remove { this.hooks.FlagEvaluated -= value; }
}

/// <inheritdoc/>
public event EventHandler<ConfigFetchedEventArgs>? ConfigFetched
{
add { this.hooks.ConfigFetched += value; }
remove { this.hooks.ConfigFetched -= value; }
}

/// <inheritdoc/>
public event EventHandler<ConfigChangedEventArgs>? ConfigChanged
{
Expand Down
8 changes: 4 additions & 4 deletions src/ConfigCatClient/ConfigService/AutoPollConfigService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -146,10 +146,10 @@ public async ValueTask<ProjectConfig> GetConfigAsync(CancellationToken cancellat
return await this.ConfigCache.GetAsync(base.CacheKey, cancellationToken).ConfigureAwait(false);
}

protected override void OnConfigFetched(ProjectConfig newConfig)
protected override void OnConfigFetched(in FetchResult fetchResult, bool initiatedByUser)
{
base.OnConfigFetched(newConfig);
SignalInitialization();
base.OnConfigFetched(fetchResult, initiatedByUser);
}

protected override void SetOnlineCoreSynchronized()
Expand Down Expand Up @@ -214,7 +214,7 @@ private async ValueTask PollCoreAsync(bool isFirstIteration, CancellationToken c
{
if (!IsOffline)
{
await RefreshConfigCoreAsync(latestConfig, cancellationToken).ConfigureAwait(false);
await RefreshConfigCoreAsync(latestConfig, initiatedByUser: false, cancellationToken).ConfigureAwait(false);
}
}
else
Expand All @@ -227,7 +227,7 @@ private async ValueTask PollCoreAsync(bool isFirstIteration, CancellationToken c
if (!IsOffline)
{
var latestConfig = await this.ConfigCache.GetAsync(base.CacheKey, cancellationToken).ConfigureAwait(false);
await RefreshConfigCoreAsync(latestConfig, cancellationToken).ConfigureAwait(false);
await RefreshConfigCoreAsync(latestConfig, initiatedByUser: false, cancellationToken).ConfigureAwait(false);
}
}
}
Expand Down
25 changes: 14 additions & 11 deletions src/ConfigCatClient/ConfigService/ConfigServiceBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public virtual RefreshResult RefreshConfig()
if (!IsOffline)
{
var latestConfig = this.ConfigCache.Get(this.CacheKey);
var configWithFetchResult = RefreshConfigCore(latestConfig);
var configWithFetchResult = RefreshConfigCore(latestConfig, initiatedByUser: true);
return RefreshResult.From(configWithFetchResult.Item2);
}
else
Expand All @@ -84,7 +84,7 @@ public virtual RefreshResult RefreshConfig()
}
}

protected ConfigWithFetchResult RefreshConfigCore(ProjectConfig latestConfig)
protected ConfigWithFetchResult RefreshConfigCore(ProjectConfig latestConfig, bool initiatedByUser)
{
var fetchResult = this.ConfigFetcher.Fetch(latestConfig);

Expand All @@ -96,11 +96,11 @@ protected ConfigWithFetchResult RefreshConfigCore(ProjectConfig latestConfig)
latestConfig = fetchResult.Config;
}

OnConfigFetched(fetchResult.Config);
OnConfigFetched(fetchResult, initiatedByUser);

if (fetchResult.IsSuccess)
{
OnConfigChanged(fetchResult.Config);
OnConfigChanged(fetchResult);
}

return new ConfigWithFetchResult(latestConfig, fetchResult);
Expand All @@ -111,7 +111,7 @@ public virtual async ValueTask<RefreshResult> RefreshConfigAsync(CancellationTok
if (!IsOffline)
{
var latestConfig = await this.ConfigCache.GetAsync(this.CacheKey, cancellationToken).ConfigureAwait(false);
var configWithFetchResult = await RefreshConfigCoreAsync(latestConfig, cancellationToken).ConfigureAwait(false);
var configWithFetchResult = await RefreshConfigCoreAsync(latestConfig, initiatedByUser: true, cancellationToken).ConfigureAwait(false);
return RefreshResult.From(configWithFetchResult.Item2);
}
else
Expand All @@ -121,7 +121,7 @@ public virtual async ValueTask<RefreshResult> RefreshConfigAsync(CancellationTok
}
}

protected async Task<ConfigWithFetchResult> RefreshConfigCoreAsync(ProjectConfig latestConfig, CancellationToken cancellationToken)
protected async Task<ConfigWithFetchResult> RefreshConfigCoreAsync(ProjectConfig latestConfig, bool initiatedByUser, CancellationToken cancellationToken)
{
var fetchResult = await this.ConfigFetcher.FetchAsync(latestConfig, cancellationToken).ConfigureAwait(false);

Expand All @@ -133,23 +133,26 @@ protected async Task<ConfigWithFetchResult> RefreshConfigCoreAsync(ProjectConfig
latestConfig = fetchResult.Config;
}

OnConfigFetched(fetchResult.Config);
OnConfigFetched(fetchResult, initiatedByUser);

if (fetchResult.IsSuccess)
{
OnConfigChanged(fetchResult.Config);
OnConfigChanged(fetchResult);
}

return new ConfigWithFetchResult(latestConfig, fetchResult);
}

protected virtual void OnConfigFetched(ProjectConfig newConfig) { }
protected virtual void OnConfigFetched(in FetchResult fetchResult, bool initiatedByUser)
{
this.Hooks.RaiseConfigFetched(RefreshResult.From(fetchResult), initiatedByUser);
}

protected virtual void OnConfigChanged(ProjectConfig newConfig)
protected virtual void OnConfigChanged(in FetchResult fetchResult)
{
this.Logger.Debug("config changed");

this.Hooks.RaiseConfigChanged(newConfig.Config ?? new Config());
this.Hooks.RaiseConfigChanged(fetchResult.Config.Config ?? new Config());
}

public bool IsOffline
Expand Down
4 changes: 2 additions & 2 deletions src/ConfigCatClient/ConfigService/LazyLoadConfigService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public ProjectConfig GetConfig()

if (!IsOffline)
{
var configWithFetchResult = RefreshConfigCore(cachedConfig);
var configWithFetchResult = RefreshConfigCore(cachedConfig, initiatedByUser: false);
return configWithFetchResult.Item1;
}
}
Expand All @@ -51,7 +51,7 @@ public async ValueTask<ProjectConfig> GetConfigAsync(CancellationToken cancellat

if (!IsOffline)
{
var configWithFetchResult = await RefreshConfigCoreAsync(cachedConfig, cancellationToken).ConfigureAwait(false);
var configWithFetchResult = await RefreshConfigCoreAsync(cachedConfig, initiatedByUser: false, cancellationToken).ConfigureAwait(false);
return configWithFetchResult.Item1;
}
}
Expand Down
7 changes: 7 additions & 0 deletions src/ConfigCatClient/Configuration/ConfigCatClientOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,13 @@ public event EventHandler<FlagEvaluatedEventArgs>? FlagEvaluated
remove { this.hooks.FlagEvaluated -= value; }
}

/// <inheritdoc/>
public event EventHandler<ConfigFetchedEventArgs>? ConfigFetched
{
add { this.hooks.ConfigFetched += value; }
remove { this.hooks.ConfigFetched -= value; }
}

/// <inheritdoc/>
public event EventHandler<ConfigChangedEventArgs>? ConfigChanged
{
Expand Down
25 changes: 25 additions & 0 deletions src/ConfigCatClient/Hooks/ConfigFetchedEventArgs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System;

namespace ConfigCat.Client;

/// <summary>
/// Provides data for the <see cref="ConfigCatClient.ConfigFetched"/> event.
/// </summary>
public class ConfigFetchedEventArgs : EventArgs
{
internal ConfigFetchedEventArgs(RefreshResult result, bool initiatedByUser)
{
Result = result;
InitiatedByUser = initiatedByUser;
}

/// <summary>
/// The result of the fetch operation.
/// </summary>
public RefreshResult Result { get; }

/// <summary>
/// Indicates whether the fetch operation was initiated by the user or by the SDK.
/// </summary>
public bool InitiatedByUser { get; }
}
17 changes: 17 additions & 0 deletions src/ConfigCatClient/Hooks/Hooks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ public void RaiseClientReady()
public void RaiseFlagEvaluated(EvaluationDetails evaluationDetails)
=> this.events.RaiseFlagEvaluated(this.client, evaluationDetails);

public void RaiseConfigFetched(RefreshResult result, bool initiatedByUser)
=> this.events.RaiseConfigFetched(this.client, result, initiatedByUser);

public void RaiseConfigChanged(IConfig newConfig)
=> this.events.RaiseConfigChanged(this.client, newConfig);

Expand All @@ -57,6 +60,12 @@ public event EventHandler<FlagEvaluatedEventArgs>? FlagEvaluated
remove { this.events.FlagEvaluated -= value; }
}

public event EventHandler<ConfigFetchedEventArgs>? ConfigFetched
{
add { this.events.ConfigFetched += value; }
remove { this.events.ConfigFetched -= value; }
}

public event EventHandler<ConfigChangedEventArgs>? ConfigChanged
{
add { this.events.ConfigChanged += value; }
Expand All @@ -73,11 +82,13 @@ public class Events : IProvidesHooks
{
public virtual void RaiseClientReady(IConfigCatClient? client) { /* intentional no-op */ }
public virtual void RaiseFlagEvaluated(IConfigCatClient? client, EvaluationDetails evaluationDetails) { /* intentional no-op */ }
public virtual void RaiseConfigFetched(IConfigCatClient? client, RefreshResult result, bool initiatedByUser) { /* intentional no-op */ }
public virtual void RaiseConfigChanged(IConfigCatClient? client, IConfig newConfig) { /* intentional no-op */ }
public virtual void RaiseError(IConfigCatClient? client, string message, Exception? exception) { /* intentional no-op */ }

public virtual event EventHandler? ClientReady { add { /* intentional no-op */ } remove { /* intentional no-op */ } }
public virtual event EventHandler<FlagEvaluatedEventArgs>? FlagEvaluated { add { /* intentional no-op */ } remove { /* intentional no-op */ } }
public virtual event EventHandler<ConfigFetchedEventArgs>? ConfigFetched { add { /* intentional no-op */ } remove { /* intentional no-op */ } }
public virtual event EventHandler<ConfigChangedEventArgs>? ConfigChanged { add { /* intentional no-op */ } remove { /* intentional no-op */ } }
public virtual event EventHandler<ConfigCatClientErrorEventArgs>? Error { add { /* intentional no-op */ } remove { /* intentional no-op */ } }
}
Expand All @@ -94,6 +105,11 @@ public override void RaiseFlagEvaluated(IConfigCatClient? client, EvaluationDeta
FlagEvaluated?.Invoke(client, new FlagEvaluatedEventArgs(evaluationDetails));
}

public override void RaiseConfigFetched(IConfigCatClient? client, RefreshResult result, bool initiatedByUser)
{
ConfigFetched?.Invoke(client, new ConfigFetchedEventArgs(result, initiatedByUser));
}

public override void RaiseConfigChanged(IConfigCatClient? client, IConfig newConfig)
{
ConfigChanged?.Invoke(client, new ConfigChangedEventArgs(newConfig));
Expand All @@ -106,6 +122,7 @@ public override void RaiseError(IConfigCatClient? client, string message, Except

public override event EventHandler? ClientReady;
public override event EventHandler<FlagEvaluatedEventArgs>? FlagEvaluated;
public override event EventHandler<ConfigFetchedEventArgs>? ConfigFetched;
public override event EventHandler<ConfigChangedEventArgs>? ConfigChanged;
public override event EventHandler<ConfigCatClientErrorEventArgs>? Error;
}
Expand Down
7 changes: 6 additions & 1 deletion src/ConfigCatClient/Hooks/IProvidesHooks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@ public interface IProvidesHooks
event EventHandler<FlagEvaluatedEventArgs>? FlagEvaluated;

/// <summary>
/// Occurs after the locally cached config has been updated.
/// Occurs after attempting to refresh the locally cached config by fetching the latest version from the remote server.
/// </summary>
event EventHandler<ConfigFetchedEventArgs>? ConfigFetched;

/// <summary>
/// Occurs after the locally cached config has been updated to a newer version.
/// </summary>
event EventHandler<ConfigChangedEventArgs>? ConfigChanged;

Expand Down
16 changes: 12 additions & 4 deletions src/ConfigCatClient/Hooks/SafeHooksWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,24 @@ public SafeHooksWrapper(Hooks hooks)
}

[MethodImpl(MethodImplOptions.NoInlining)]
public void RaiseClientReady() => Hooks.RaiseClientReady();
public void RaiseClientReady()
=> Hooks.RaiseClientReady();

[MethodImpl(MethodImplOptions.NoInlining)]
public void RaiseFlagEvaluated(EvaluationDetails evaluationDetails) => Hooks.RaiseFlagEvaluated(evaluationDetails);
public void RaiseFlagEvaluated(EvaluationDetails evaluationDetails)
=> Hooks.RaiseFlagEvaluated(evaluationDetails);

[MethodImpl(MethodImplOptions.NoInlining)]
public void RaiseConfigChanged(IConfig newConfig) => Hooks.RaiseConfigChanged(newConfig);
public void RaiseConfigFetched(RefreshResult result, bool initiatedByUser)
=> Hooks.RaiseConfigFetched(result, initiatedByUser);

[MethodImpl(MethodImplOptions.NoInlining)]
public void RaiseError(string message, Exception? exception) => Hooks.RaiseError(message, exception);
public void RaiseConfigChanged(IConfig newConfig)
=> Hooks.RaiseConfigChanged(newConfig);

[MethodImpl(MethodImplOptions.NoInlining)]
public void RaiseError(string message, Exception? exception)
=> Hooks.RaiseError(message, exception);

public static implicit operator SafeHooksWrapper(Hooks? hooks) => hooks is not null ? new SafeHooksWrapper(hooks) : default;
}

0 comments on commit 7fcf0bb

Please sign in to comment.