Skip to content

Commit

Permalink
Merge branch 'main' into v1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
aritchie committed Jun 29, 2024
2 parents 8592965 + e93e84a commit d17b7ee
Show file tree
Hide file tree
Showing 42 changed files with 677 additions and 500 deletions.
3 changes: 3 additions & 0 deletions Sample/Contracts/CacheRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace Sample.Contracts;

public record CacheRequest : IRequest<string>;
3 changes: 0 additions & 3 deletions Sample/Contracts/CachedRequest.cs

This file was deleted.

9 changes: 1 addition & 8 deletions Sample/Contracts/MyMessageContracts.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
using Shiny.Mediator.Middleware;

namespace Sample.Contracts;

public record MyMessageRequest(string Arg, bool FireAndForgetEvents) : IRequest<MyMessageResponse>, ICacheItem
{
public string CacheKey { get; }
};

public record MyMessageRequest(string Arg, bool FireAndForgetEvents) : IRequest<MyMessageResponse>;
public record MyMessageResponse(string Response);

public record MyMessageEvent(string Arg, bool FireAndForgetEvents) : IEvent;
3 changes: 3 additions & 0 deletions Sample/Contracts/OfflineRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace Sample.Contracts;

public record OfflineRequest : IRequest<string>;
8 changes: 4 additions & 4 deletions Sample/Handlers/CachedRequestHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ namespace Sample.Handlers;


[RegisterHandler]
public class CachedRequestHandler : IRequestHandler<CachedRequest, string>
public class CachedRequestHandler : IRequestHandler<CacheRequest, string>
{
[Cache(MaxAgeSeconds = 20)]
public Task<string> Handle(CachedRequest request, CancellationToken cancellationToken)
[Cache(AbsoluteExpirationSeconds = 20)]
public Task<string> Handle(CacheRequest request, CancellationToken cancellationToken)
{
var r = DateTimeOffset.UtcNow.ToLocalTime().ToString("h:mm:ss tt");
var r = DateTimeOffset.Now.ToString("h:mm:ss tt");
return Task.FromResult(r);
}
}
15 changes: 15 additions & 0 deletions Sample/Handlers/OfflineRequestHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Sample.Contracts;

namespace Sample.Handlers;


[RegisterHandler]
public class OfflineRequestHandler : IRequestHandler<OfflineRequest, string>
{
[OfflineAvailable(true)]
public Task<string> Handle(OfflineRequest request, CancellationToken cancellationToken)
{
var r = DateTimeOffset.Now.ToString("h:mm:ss tt");
return Task.FromResult(r);
}
}
3 changes: 2 additions & 1 deletion Sample/Handlers/SingletonRequestHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ namespace Sample.Handlers;
[TimedLogging(3000)]
public class SingletonRequestHandler(IMediator mediator, AppSqliteConnection data) : IRequestHandler<MyMessageRequest, MyMessageResponse>
{
[Cache(Storage = StoreType.File, MaxAgeSeconds = 30, OnlyForOffline = true)]
// [Cache(Storage = StoreType.File, MaxAgeSeconds = 30, OnlyForOffline = true)]
[OfflineAvailable]
public async Task<MyMessageResponse> Handle(MyMessageRequest request, CancellationToken cancellationToken)
{
var e = new MyMessageEvent(
Expand Down
4 changes: 4 additions & 0 deletions Sample/MauiProgram.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ public static MauiApp CreateMauiApp()
// builder.AddTimeout(TimeSpan.FromSeconds(2.0));
// })
// )
.AddMemoryCaching(x =>
{
x.ExpirationScanFrequency = TimeSpan.FromSeconds(5);
})
);
builder.Services.AddDiscoveredMediatorHandlersFromSample();

Expand Down
1 change: 1 addition & 0 deletions Sample/Sample.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@

<ItemGroup>
<ProjectReference Include="..\src\Shiny.Mediator.Blazor\Shiny.Mediator.Blazor.csproj" />
<ProjectReference Include="..\src\Shiny.Mediator.Caching\Shiny.Mediator.Caching.csproj" />
<ProjectReference Include="..\src\Shiny.Mediator.Contracts\Shiny.Mediator.Contracts.csproj"/>
<ProjectReference Include="..\src\Shiny.Mediator.Maui\Shiny.Mediator.Maui.csproj"/>
<ProjectReference Include="..\src\Shiny.Mediator.Resilience\Shiny.Mediator.Resilience.csproj" />
Expand Down
8 changes: 8 additions & 0 deletions Sample/TriggerPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@
Command="{Binding ErrorTrap}" />
</TableSection>

<TableSection Title="Offline">
<TextCell Text="Request"
Command="{Binding OfflineCommand}" />

<TextCell Text="Value"
Detail="{Binding OfflineValue}" />
</TableSection>

<TableSection Title="Cache">
<TextCell Text="Clear" Command="{Binding CacheClear}" />
<TextCell Text="Request" Command="{Binding CacheRequest}" />
Expand Down
14 changes: 12 additions & 2 deletions Sample/TriggerViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Microsoft.Extensions.Caching.Memory;
using Sample.Contracts;

namespace Sample;
Expand All @@ -11,6 +12,7 @@ public class TriggerViewModel : ViewModel, IEventHandler<MyMessageEvent>
public TriggerViewModel(
BaseServices services,
IMediator mediator,
IMemoryCache cache,
AppSqliteConnection data
)
: base(services)
Expand Down Expand Up @@ -74,7 +76,7 @@ await data.Log(

this.CacheClear = ReactiveCommand.CreateFromTask(async () =>
{
await mediator.Send(new FlushAllCacheRequest());
cache.Clear();
await this.Dialogs.Alert("Cache Cleared");
});

Expand All @@ -85,14 +87,19 @@ await data.Log(
});
this.CacheRequest = ReactiveCommand.CreateFromTask(async () =>
{
this.CacheValue = await mediator.Request(new CachedRequest());
this.CacheValue = await mediator.Request(new CacheRequest());
});

this.ResilientCommand = ReactiveCommand.CreateFromTask(async () =>
{
this.ResilientValue = await mediator.Request(new ResilientRequest());
});

this.OfflineCommand = ReactiveCommand.CreateFromTask(async () =>
{
this.OfflineValue = await mediator.Request(new OfflineRequest());
});

this.RefreshTimerStart = ReactiveCommand.CreateFromTask(async () =>
{
var en = mediator.Request(new AutoRefreshRequest(), this.DeactivateToken).GetAsyncEnumerator(this.DeactivateToken);
Expand All @@ -115,6 +122,9 @@ public Task Handle(MyMessageEvent @event, CancellationToken cancellationToken)
}


public ICommand OfflineCommand { get; }
[Reactive] public string OfflineValue { get; private set; }

public ICommand CancelStream { get; }
public ICommand ErrorTrap { get; }
public ICommand TriggerCommand { get; }
Expand Down
6 changes: 6 additions & 0 deletions ShinyMediator.sln
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shiny.Mediator.Blazor", "sr
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shiny.Mediator.Resilience", "src\Shiny.Mediator.Resilience\Shiny.Mediator.Resilience.csproj", "{1DDF878B-0EDF-4C32-813C-7995427D3387}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shiny.Mediator.Caching", "src\Shiny.Mediator.Caching\Shiny.Mediator.Caching.csproj", "{0F0B73E3-165F-44E1-B0CF-917231D3C670}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -68,5 +70,9 @@ Global
{1DDF878B-0EDF-4C32-813C-7995427D3387}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1DDF878B-0EDF-4C32-813C-7995427D3387}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1DDF878B-0EDF-4C32-813C-7995427D3387}.Release|Any CPU.Build.0 = Release|Any CPU
{0F0B73E3-165F-44E1-B0CF-917231D3C670}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0F0B73E3-165F-44E1-B0CF-917231D3C670}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0F0B73E3-165F-44E1-B0CF-917231D3C670}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0F0B73E3-165F-44E1-B0CF-917231D3C670}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
11 changes: 11 additions & 0 deletions src/Shiny.Mediator.Caching/CacheAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using Microsoft.Extensions.Caching.Memory;

namespace Shiny.Mediator;

[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
public class CacheAttribute : Attribute
{
public CacheItemPriority Priority { get; set; } = CacheItemPriority.Normal;
public int AbsoluteExpirationSeconds { get; set; }
public int SlidingExpirationSeconds { get; set; }
}
21 changes: 21 additions & 0 deletions src/Shiny.Mediator.Caching/CacheExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using Shiny.Mediator.Caching.Infrastructure;
using Shiny.Mediator.Middleware;

namespace Shiny.Mediator;


public static class CacheExtensions
{
public static ShinyConfigurator AddMemoryCaching(this ShinyConfigurator cfg, Action<MemoryCacheOptions> configureCache)
{
cfg.Services.AddMemoryCache(configureCache);
cfg.Services.AddSingleton<IEventHandler<FlushAllStoresEvent>, FlushCacheEventHandler>();
cfg.AddOpenRequestMiddleware(typeof(CachingRequestMiddleware<,>));
return cfg;
}

public static void Clear(this IMemoryCache cache)
=> (cache as MemoryCache)?.Clear();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using Microsoft.Extensions.Caching.Memory;

namespace Shiny.Mediator.Caching.Infrastructure;


public class CachingRequestMiddleware<TRequest, TResult>(IMemoryCache cache) : IRequestMiddleware<TRequest, TResult>
{
public async Task<TResult> Process(
TRequest request,
RequestHandlerDelegate<TResult> next,
IRequestHandler requestHandler,
CancellationToken cancellationToken
)
{
if (typeof(TResult) == typeof(Unit))
return await next().ConfigureAwait(false);

var cfg = requestHandler.GetHandlerHandleMethodAttribute<TRequest, CacheAttribute>();
if (cfg == null)
return await next().ConfigureAwait(false);

var cacheKey = this.GetCacheKey(request!, requestHandler);
var result = await cache.GetOrCreateAsync<TResult>(
cacheKey,
entry =>
{
entry.Priority = cfg.Priority;

if (cfg.AbsoluteExpirationSeconds > 0)
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(cfg.AbsoluteExpirationSeconds);

if (cfg.SlidingExpirationSeconds > 0)
entry.SlidingExpiration = TimeSpan.FromSeconds(cfg.SlidingExpirationSeconds);

return next();
}
);

return result!;
}


protected virtual string GetCacheKey(object request, IRequestHandler handler)
{
if (request is IRequestKey keyProvider)
return keyProvider.GetKey();

var t = request.GetType();
var key = $"{t.Namespace}_{t.Name}";
return key;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Microsoft.Extensions.Caching.Memory;
using Shiny.Mediator.Middleware;

namespace Shiny.Mediator.Caching.Infrastructure;


public class FlushCacheEventHandler(IMemoryCache cache) : IEventHandler<FlushAllStoresEvent>
{
public Task Handle(FlushAllStoresEvent @event, CancellationToken cancellationToken)
{
cache.Clear();
return Task.CompletedTask;
}
}
17 changes: 17 additions & 0 deletions src/Shiny.Mediator.Caching/Shiny.Mediator.Caching.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Shiny.Mediator\Shiny.Mediator.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="8.0.0" />
</ItemGroup>

</Project>
10 changes: 10 additions & 0 deletions src/Shiny.Mediator.Contracts/IRequestKey.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace Shiny.Mediator;

/// <summary>
/// This is viewed by replay, cache, and various other services where you can control an entry
/// Simply mark your IRequest or IStreamRequest and provide the necessary key to determine uniqueness
/// </summary>
public interface IRequestKey
{
string GetKey();
}
11 changes: 11 additions & 0 deletions src/Shiny.Mediator.Maui/Infrastructure/IStorageManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace Shiny.Mediator.Infrastructure;

public interface IStorageManager
{
void Store(object request, object result, bool isPeristent);

TResult? Get<TResult>(object request, bool isPeristent);

void ClearAll();
// TODO: remove(request) & clearall, clearbyrequesttype
}
Loading

0 comments on commit d17b7ee

Please sign in to comment.