Skip to content

Commit

Permalink
More samples and working stream middleware
Browse files Browse the repository at this point in the history
  • Loading branch information
aritchie committed Jun 20, 2024
1 parent 9196902 commit cfb988e
Show file tree
Hide file tree
Showing 22 changed files with 309 additions and 148 deletions.
3 changes: 3 additions & 0 deletions Sample/Contracts/AutoRefreshRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace Sample.Contracts;

public record AutoRefreshRequest : IStreamRequest<string>;
3 changes: 3 additions & 0 deletions Sample/Contracts/CachedRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace Sample.Contracts;

public record CachedRequest : IRequest<string>;
3 changes: 3 additions & 0 deletions Sample/Contracts/ResilientRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace Sample.Contracts;

public record ResilientRequest : IRequest<string>;
14 changes: 14 additions & 0 deletions Sample/Handlers/AutoRefreshStreamRequestHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System.Runtime.CompilerServices;
using Sample.Contracts;

namespace Sample.Handlers;

[RegisterHandler]
public class AutoRefreshStreamRequestHandler : IStreamRequestHandler<AutoRefreshRequest, string>
{
[TimerRefresh(3000)]
public async IAsyncEnumerable<string> Handle(AutoRefreshRequest request, [EnumeratorCancellation] CancellationToken cancellationToken)
{
yield return DateTimeOffset.Now.ToString("h:mm:ss tt");
}
}
15 changes: 15 additions & 0 deletions Sample/Handlers/CachedRequestHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Sample.Contracts;

namespace Sample.Handlers;


[RegisterHandler]
public class CachedRequestHandler : IRequestHandler<CachedRequest, string>
{
[Cache(MaxAgeSeconds = 20)]
public Task<string> Handle(CachedRequest request, CancellationToken cancellationToken)
{
var r = DateTimeOffset.UtcNow.ToLocalTime().ToString("h:mm:ss tt");
return Task.FromResult(r);
}
}
8 changes: 5 additions & 3 deletions Sample/Handlers/MyStreamRequestMiddleware.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
namespace Sample.Handlers;

public class MyStreamRequestMiddleware<TRequest, TResult> : IStreamRequestMiddleware<TRequest, TResult> where TRequest : IStreamRequest<TResult>
// [RegisterMiddleware]
public class MyStreamRequestMiddleware<TRequest, TResult>(ILogger<MyStreamRequestMiddleware<TRequest, TResult>> logger) : IStreamRequestMiddleware<TRequest, TResult> where TRequest : IStreamRequest<TResult>
{
public IAsyncEnumerator<TResult> Process(
public IAsyncEnumerable<TResult> Process(
TRequest request,
StreamRequestDelegate<TResult> next,
StreamRequestHandlerDelegate<TResult> next,
IStreamRequestHandler<TRequest, TResult> requestHandler,
CancellationToken cancellationToken
)
{
logger.LogInformation($"MyStreamRequestMiddleware called for {typeof(TRequest).FullName}");
return next();
}
}
23 changes: 23 additions & 0 deletions Sample/Handlers/ResilientRequestHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using Sample.Contracts;
using Shiny.Mediator.Resilience;

namespace Sample.Handlers;


[RegisterHandler]
public class ResilientRequestHandler : IRequestHandler<ResilientRequest, string>
{
static bool timeoutRequest;

[Resilient("test")]
public async Task<string> Handle(ResilientRequest request, CancellationToken cancellationToken)
{
if (timeoutRequest)
{
await Task.Delay(3000, cancellationToken);
}

timeoutRequest = !timeoutRequest;
return DateTimeOffset.UtcNow.ToString("f");
}
}
3 changes: 2 additions & 1 deletion Sample/Handlers/TickerStreamRequestHandler.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Runtime.CompilerServices;
using Sample.Contracts;

namespace Sample.Handlers;
Expand All @@ -6,7 +7,7 @@ namespace Sample.Handlers;
[RegisterHandler]
public class TickerStreamRequestHandler : IStreamRequestHandler<TickerRequest, string>
{
public async IAsyncEnumerable<string> Handle(TickerRequest request, CancellationToken cancellationToken)
public async IAsyncEnumerable<string> Handle(TickerRequest request, [EnumeratorCancellation] CancellationToken cancellationToken)
{
for (var i = 0; i < request.Repeat; i++)
{
Expand Down
17 changes: 14 additions & 3 deletions Sample/MauiProgram.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using Sample.Handlers;
using Polly;
using Polly.Retry;
using Sample.Handlers;
using Shiny.Mediator.Resilience;

namespace Sample;

Expand Down Expand Up @@ -40,17 +43,25 @@ public static MauiApp CreateMauiApp()
builder.Services.AddShinyMediator(x => x
.UseMaui()
.UseBlazor()
.AddTimerRefreshStreamMiddleware()
// .AddReplayStreamMiddleware()
.AddUserNotificationExceptionMiddleware(new UserExceptionRequestMiddlewareConfig
{
ErrorConfirm = "OK",
ErrorTitle = "OOOPS",
ErrorMessage = "You did something wrong",
ShowFullException = false
})
// .AddResiliencyMiddleware(
// ("Test", builder =>
// {
// // builder.AddRetry(new RetryStrategyOptions());
// builder.AddTimeout(TimeSpan.FromSeconds(2.0));
// })
// )
);
builder.Services.AddDiscoveredMediatorHandlersFromSample();
// builder.Services.AddSingletonAsImplementedInterfaces<ErrorRequestHandler>();


builder.Services.AddSingleton<AppSqliteConnection>();
builder.Services.AddMauiBlazorWebView();

Expand Down
28 changes: 20 additions & 8 deletions Sample/TriggerPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,20 @@
</TableSection>

<TableSection Title="Cache">
<!--TODO - clear cache-->
<TextCell Text="Clear" Command="{Binding CacheClear}" />
<TextCell Text="Request" Command="{Binding CacheRequest}" />
<TextCell Text="Value" Detail="{Binding CacheValue}" />
<TextCell Text="Cache has a 20s expiry time" />
</TableSection>

<!--
<TableSection Title="Resiliency">
<!--TODO-->
<TextCell Text="Request" Command="{Binding ResilientCommand}" />
<TextCell Text="Value" Detail="{Binding ResilientValue}" />
</TableSection>
-->

<TableSection Title="Streaming">
<TableSection Title="STREAMING - Standard">
<EntryCell Label="Repeat"
Text="{Binding StreamRepeat}"
Keyboard="Numeric" />
Expand All @@ -49,20 +55,26 @@
Text="{Binding StreamGapSeconds}"
Keyboard="Numeric" />

<TextCell Text="Run Stream"
<TextCell Text="Run"
Command="{Binding Stream}"/>

<TextCell Text="Stop"
Command="{Binding CancelStream}"/>

<TextCell Text="Last Response"
Detail="{Binding StreamLastResponse}" />
</TableSection>

<TableSection Title="Timer Refresh">
<!--start/cancel-->
<TableSection Title="STREAMING - Timer Refresh">
<TextCell Text="Start" Command="{Binding RefreshTimerStart}" />
<TextCell Text="Stop" Command="{Binding CancelStream}" />
<TextCell Text="Last Value" Detail="{Binding LastRefreshTimerValue}" />
</TableSection>

<TableSection Title="Replay">
<!--run-->
<!--
<TableSection Title="STREAMING - Replay">
</TableSection>
-->
</TableRoot>
</TableView>
</ContentPage>
53 changes: 49 additions & 4 deletions Sample/TriggerViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ AppSqliteConnection data
)
: base(services)
{
// TODO: request without response
this.TriggerCommand = ReactiveCommand.CreateFromTask(
async () =>
{
Expand All @@ -25,7 +24,6 @@ AppSqliteConnection data
this.FireAndForgetEvents
);
var result = await mediator.Request(request, this.cancelSource.Token);


await data.Log(
"TriggerViewModel-Response",
Expand All @@ -46,7 +44,7 @@ await data.Log(
await data.Log(
"TriggerViewModel-Cancel",
new MyMessageEvent(
this.Arg,
this.Arg!,
this.FireAndForgetEvents
)
);
Expand All @@ -61,7 +59,10 @@ await data.Log(

this.Stream = ReactiveCommand.CreateFromTask(async () =>
{
var stream = mediator.Request(new TickerRequest(this.StreamRepeat, this.StreamMultiplier, this.StreamGapSeconds));
var stream = mediator.Request(
new TickerRequest(this.StreamRepeat, this.StreamMultiplier, this.StreamGapSeconds),
this.DeactivateToken
);
await foreach (var item in stream)
{
this.StreamLastResponse = item;
Expand All @@ -70,6 +71,38 @@ await data.Log(
this.sub = mediator.Subscribe((MyMessageEvent @event, CancellationToken _) =>
data.Log("TriggerViewModel-Subscribe", @event)
);

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

this.CancelStream = ReactiveCommand.CreateFromTask(async () =>
{
this.Deactivate();
await this.Dialogs.Alert("All streams cancelled");
});
this.CacheRequest = ReactiveCommand.CreateFromTask(async () =>
{
this.CacheValue = await mediator.Request(new CachedRequest());
});

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

this.RefreshTimerStart = ReactiveCommand.CreateFromTask(async () =>
{
var en = mediator.Request(new AutoRefreshRequest(), this.DeactivateToken).GetAsyncEnumerator(this.DeactivateToken);
while (await en.MoveNextAsync())
{
await MainThread.InvokeOnMainThreadAsync(
() => this.LastRefreshTimerValue = en.Current
);
}
});
}


Expand All @@ -81,9 +114,21 @@ public Task Handle(MyMessageEvent @event, CancellationToken cancellationToken)
return Task.CompletedTask;
}


public ICommand CancelStream { get; }
public ICommand ErrorTrap { get; }
public ICommand TriggerCommand { get; }
public ICommand CancelCommand { get; }
public ICommand CacheRequest { get; }
public ICommand CacheClear { get; }
[Reactive] public string CacheValue { get; private set; }

[Reactive] public string LastRefreshTimerValue { get; private set; }
public ICommand RefreshTimerStart { get; }

public ICommand ResilientCommand { get; }
[Reactive] public string ResilientValue { get; private set; }

[Reactive] public string Arg { get; set; }
[Reactive] public bool FireAndForgetEvents { get; set; }

Expand Down
36 changes: 13 additions & 23 deletions src/Shiny.Mediator.Maui/MauiMediatorExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,21 @@
namespace Shiny.Mediator;


public class MauiServiceProvider : IMauiInitializeService
{
public static IServiceProvider Services { get; private set; } = null!;
public void Initialize(IServiceProvider services)
{
Services = services;
}
}


public static class MauiMediatorExtensions
{
public static ShinyConfigurator UseMaui(this ShinyConfigurator cfg, bool includeStandardMiddleware = true)
{
cfg.AddEventCollector<MauiEventCollector>();

if (includeStandardMiddleware)
{
cfg.AddEventExceptionHandlingMiddleware();
cfg.AddTimedMiddleware();
cfg.AddMainThreadEventMiddleware();

cfg.AddTimedMiddleware();
cfg.AddCacheMiddleware();
// cfg.AddUserNotificationExceptionMiddleware();
}

return cfg;
}

Expand All @@ -38,32 +30,30 @@ public static ShinyConfigurator AddTimedMiddleware(this ShinyConfigurator cfg)


public static ShinyConfigurator AddEventExceptionHandlingMiddleware(this ShinyConfigurator cfg)
{
cfg.AddOpenEventMiddleware(typeof(ExceptionHandlerEventMiddleware<>));
return cfg;
}
=> cfg.AddOpenEventMiddleware(typeof(ExceptionHandlerEventMiddleware<>));


public static ShinyConfigurator AddMainThreadEventMiddleware(this ShinyConfigurator cfg)
{
cfg.AddOpenEventMiddleware(typeof(MainTheadEventMiddleware<>));
return cfg;
}
=> cfg.AddOpenEventMiddleware(typeof(MainTheadEventMiddleware<>));


public static ShinyConfigurator AddCacheMiddleware(this ShinyConfigurator cfg)
{
cfg.Services.TryAddSingleton(Connectivity.Current);
cfg.Services.TryAddSingleton(FileSystem.Current);
cfg.Services.TryAddSingleton<CacheManager>();
cfg.Services.AddSingletonAsImplementedInterfaces<CacheHandlers>();
cfg.AddOpenRequestMiddleware(typeof(CacheRequestMiddleware<,>));
return cfg;
}


public static ShinyConfigurator AddReplayStreamMiddleware(this ShinyConfigurator configurator)
public static ShinyConfigurator AddReplayStreamMiddleware(this ShinyConfigurator cfg)
{
configurator.AddOpenStreamMiddleware(typeof(ReplayStreamMiddleware<,>));
return configurator;
cfg.Services.TryAddSingleton(Connectivity.Current);
cfg.Services.TryAddSingleton(FileSystem.Current);
cfg.AddOpenStreamMiddleware(typeof(ReplayStreamMiddleware<,>));
return cfg;
}


Expand Down
Loading

0 comments on commit cfb988e

Please sign in to comment.