Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@
<PackageVersion Include="Serilog.AspNetCore" Version="10.0.0" />
<PackageVersion Include="Serilog.Sinks.Async" Version="2.1.0" />
<PackageVersion Include="Serilog.Sinks.Console" Version="6.1.1" />
<PackageVersion Include="TUnit" Version="1.43.2" />
<PackageVersion Include="TUnit.Assertions" Version="1.43.2" />
<PackageVersion Include="TUnit.Core" Version="1.43.2" />
<PackageVersion Include="TUnit.Playwright" Version="1.43.2" />
<PackageVersion Include="TUnit" Version="1.43.11" />
<PackageVersion Include="TUnit.Assertions" Version="1.43.11" />
<PackageVersion Include="TUnit.Core" Version="1.43.11" />
<PackageVersion Include="TUnit.Playwright" Version="1.43.11" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ internal readonly record struct InfiniFrameWindowEventsSnapshot(
Action<IInfiniFrameWindow>[] WindowMinimized,
Action<IInfiniFrameWindow, string>[] WebMessageReceived,
Action<IInfiniFrameWindow>[] WindowClosingRequested,
NetClosingDelegate[] WindowClosing,
Func<IInfiniFrameWindow, EventArgs?, bool>[] WindowClosing,
Action<IInfiniFrameWindow>[] WindowCreating,
Action<IInfiniFrameWindow>[] WindowCreated
);
8 changes: 0 additions & 8 deletions src/InfiniFrame.Shared/Delegates/NetClosingDelegate.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ namespace InfiniFrame;
// ---------------------------------------------------------------------------------------------------------------------
// Code
// ---------------------------------------------------------------------------------------------------------------------
public delegate Stream? NetCustomSchemeDelegate(object sender, string scheme, string url, out string? contentType);
public delegate Stream? NetCustomSchemeDelegate(IInfiniFrameWindow sender, string scheme, string url, out string? contentType);
Original file line number Diff line number Diff line change
Expand Up @@ -176,11 +176,9 @@ public static T RegisterWindowClosingRequestedHandler<T>(this T builder, Action<
/// <returns>
/// Returns the current <see cref="IHasInfiniFrameEvents" /> instance.
/// </returns>
/// <param name="handler">
/// <see cref="NetClosingDelegate" />
/// </param>
/// <param name="builder">The builder to register the handler for.</param>
public static T RegisterWindowClosingHandler<T>(this T builder, NetClosingDelegate handler) where T : IHasInfiniFrameEvents {
/// <param name="handler">The handler that will be invoked</param>
public static T RegisterWindowClosingHandler<T>(this T builder, Func<IInfiniFrameWindow,EventArgs?, bool> handler) where T : IHasInfiniFrameEvents {
builder.Events.WindowClosing.Add(handler);
return builder;
}
Expand Down
24 changes: 12 additions & 12 deletions src/InfiniFrame.Shared/IInfiniFrameWindowEvents.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,18 @@ namespace InfiniFrame;
// Code
// ---------------------------------------------------------------------------------------------------------------------
public interface IInfiniFrameWindowEvents {
InfiniFrameOrderedEvent<Point> WindowLocationChanged { get; }
InfiniFrameOrderedEvent<Size> WindowSizeChanged { get; }
InfiniFrameOrderedEvent WindowFocusIn { get; }
InfiniFrameOrderedEvent WindowMaximized { get; }
InfiniFrameOrderedEvent WindowRestored { get; }
InfiniFrameOrderedEvent WindowFocusOut { get; }
InfiniFrameOrderedEvent WindowMinimized { get; }
InfiniFrameOrderedEvent<string> WebMessageReceived { get; }
InfiniFrameOrderedEvent WindowClosingRequested { get; }
InfiniFrameOrderedClosingEvent WindowClosing { get; }
InfiniFrameOrderedEvent WindowCreating { get; }
InfiniFrameOrderedEvent WindowCreated { get; }
OrderedEvent<Point> WindowLocationChanged { get; }
OrderedEvent<Size> WindowSizeChanged { get; }
OrderedEvent WindowFocusIn { get; }
OrderedEvent WindowMaximized { get; }
OrderedEvent WindowRestored { get; }
OrderedEvent WindowFocusOut { get; }
OrderedEvent WindowMinimized { get; }
OrderedEvent<string> WebMessageReceived { get; }
OrderedEvent WindowClosingRequested { get; }
OrderedResultEvent<EventArgs?, bool> WindowClosing { get; }
OrderedEvent WindowCreating { get; }
OrderedEvent WindowCreated { get; }

void CompleteSetup(IInfiniFrameWindow sender);

Expand Down
43 changes: 0 additions & 43 deletions src/InfiniFrame.Shared/Utilities/InfiniFrameOrderedClosingEvent.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace InfiniFrame.Utilities;
// ---------------------------------------------------------------------------------------------------------------------
// Code
// ---------------------------------------------------------------------------------------------------------------------
public class InfiniFrameOrderedEvent {
public class OrderedEvent {
private ImmutableArray<Action<IInfiniFrameWindow>> _handlers = ImmutableArray<Action<IInfiniFrameWindow>>.Empty;
public ImmutableArray<Action<IInfiniFrameWindow>> Snapshot => _handlers;

Expand Down Expand Up @@ -39,10 +39,13 @@ public void Invoke(IInfiniFrameWindow window) {
}
}

public class InfiniFrameOrderedEvent<TPayload> {
public class OrderedEvent<TPayload> {
private ImmutableArray<Action<IInfiniFrameWindow, TPayload>> _handlers = ImmutableArray<Action<IInfiniFrameWindow, TPayload>>.Empty;
public ImmutableArray<Action<IInfiniFrameWindow, TPayload>> Snapshot => _handlers;

// -----------------------------------------------------------------------------------------------------------------
// Methods
// -----------------------------------------------------------------------------------------------------------------
public void Add(Action<IInfiniFrameWindow, TPayload> handler) {
ArgumentNullException.ThrowIfNull(handler);
ImmutableInterlocked.Update(ref _handlers, transformer: static (current, item) => current.Add(item), handler);
Expand All @@ -58,4 +61,4 @@ public void Invoke(IInfiniFrameWindow window, TPayload payload) {
handler(window, payload);
}
}
}
}
42 changes: 42 additions & 0 deletions src/InfiniFrame.Shared/Utilities/OrderedResultEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// ---------------------------------------------------------------------------------------------------------------------
// Imports
// ---------------------------------------------------------------------------------------------------------------------
using System.Collections.Immutable;

namespace InfiniFrame.Utilities;
// ---------------------------------------------------------------------------------------------------------------------
// Code
// ---------------------------------------------------------------------------------------------------------------------
public class OrderedResultEvent<TPayload, TResult> {
private ImmutableArray<Func<IInfiniFrameWindow, TPayload, TResult>> _handlers = ImmutableArray<Func<IInfiniFrameWindow, TPayload, TResult>>.Empty;
public ImmutableArray<Func<IInfiniFrameWindow, TPayload, TResult>> Snapshot => _handlers;

// -----------------------------------------------------------------------------------------------------------------
// Methods
// -----------------------------------------------------------------------------------------------------------------
public void Add(Func<IInfiniFrameWindow, TPayload, TResult> handler) {
ArgumentNullException.ThrowIfNull(handler);
ImmutableInterlocked.Update(ref _handlers, transformer: static (current, item) => current.Add(item), handler);
}

public void Remove(Func<IInfiniFrameWindow, TPayload, TResult> handler) {
ArgumentNullException.ThrowIfNull(handler);
ImmutableInterlocked.Update(ref _handlers, transformer: static (current, item) => current.Remove(item), handler);
}

public TResult?[] Invoke(IInfiniFrameWindow window, TPayload payload) {
var results = new TResult?[_handlers.Length];
for (int i = 0; i < _handlers.Length; i++) {
Func<IInfiniFrameWindow, TPayload, TResult> handler = _handlers[i];

try {
results[i] = handler(window, payload);
}
catch (Exception ex) when (ex is not OperationCanceledException) {
results[i] = default;
}
}

return results.ToArray();
}
}
31 changes: 16 additions & 15 deletions src/InfiniFrame/InfiniFrameWindowEvents.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,18 @@ namespace InfiniFrame;
public class InfiniFrameWindowEvents : IInfiniFrameWindowEvents {

private IInfiniFrameWindow Sender { get; set; } = null!;
public InfiniFrameOrderedEvent<Point> WindowLocationChanged { get; } = new();
public InfiniFrameOrderedEvent<Size> WindowSizeChanged { get; } = new();
public InfiniFrameOrderedEvent WindowFocusIn { get; } = new();
public InfiniFrameOrderedEvent WindowMaximized { get; } = new();
public InfiniFrameOrderedEvent WindowRestored { get; } = new();
public InfiniFrameOrderedEvent WindowFocusOut { get; } = new();
public InfiniFrameOrderedEvent WindowMinimized { get; } = new();
public InfiniFrameOrderedEvent<string> WebMessageReceived { get; } = new();
public InfiniFrameOrderedEvent WindowClosingRequested { get; } = new();
public InfiniFrameOrderedClosingEvent WindowClosing { get; } = new();
public InfiniFrameOrderedEvent WindowCreating { get; } = new();
public InfiniFrameOrderedEvent WindowCreated { get; } = new();
public OrderedEvent<Point> WindowLocationChanged { get; } = new();
public OrderedEvent<Size> WindowSizeChanged { get; } = new();
public OrderedEvent WindowFocusIn { get; } = new();
public OrderedEvent WindowMaximized { get; } = new();
public OrderedEvent WindowRestored { get; } = new();
public OrderedEvent WindowFocusOut { get; } = new();
public OrderedEvent WindowMinimized { get; } = new();
public OrderedEvent<string> WebMessageReceived { get; } = new();
public OrderedEvent WindowClosingRequested { get; } = new();
public OrderedResultEvent<EventArgs?, bool> WindowClosing { get; } = new();
public OrderedEvent WindowCreating { get; } = new();
public OrderedEvent WindowCreated { get; } = new();

// -----------------------------------------------------------------------------------------------------------------
// Methods
Expand Down Expand Up @@ -103,10 +103,11 @@ public void OnWindowClosingRequested() {
public byte OnWindowClosing() {
//C++ handles bool values as a single byte, C# uses 4 bytes
byte noClose = 0;
bool? doNotClose = WindowClosing.Invoke(Sender);
if (doNotClose ?? false)
bool[] doNotClose = WindowClosing.Invoke(Sender, null);
if (doNotClose.Any(r => r)) {
noClose = 1;

}

return noClose;
}

Expand Down
9 changes: 4 additions & 5 deletions src/InfiniFrame/StaticAssets/StaticAssetSchemeHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,24 @@ public static NetCustomSchemeDelegate Create(IFileProvider fileProvider, string
// yes, C# 14 and such have out parameters in their lambas, but we need to support .NET 8.0 which does not natively have this yet
return NetCustomSchemeDelegateWrapper;

Stream? NetCustomSchemeDelegateWrapper(object sender, string scheme, string url, out string? contentType) {
Stream? NetCustomSchemeDelegateWrapper(IInfiniFrameWindow sender, string scheme, string url, out string? contentType) {
#endif
contentType = null;
if (sender is not IInfiniFrameWindow { Logger: var logger }) return null;

if (!TryGetAssetPath(url, defaultDocument, out string assetPath)) {
logger.LogDebug("Rejected custom scheme path for {Scheme}: {Url}", scheme, url);
sender.Logger.LogDebug("Rejected custom scheme path for {Scheme}: {Url}", scheme, url);
return null;
}

IFileInfo file = fileProvider.GetFileInfo(assetPath);
if (!file.Exists || file.IsDirectory) {
logger.LogDebug("Custom scheme miss for {Scheme}: {AssetPath} (from {Url})", scheme, assetPath,
sender.Logger.LogDebug("Custom scheme miss for {Scheme}: {AssetPath} (from {Url})", scheme, assetPath,
url);
return null;
}

contentType = GetContentType(assetPath);
logger.LogDebug("Custom scheme hit for {Scheme}: {AssetPath} ({ContentType})", scheme, assetPath,
sender.Logger.LogDebug("Custom scheme hit for {Scheme}: {AssetPath} ({ContentType})", scheme, assetPath,
contentType);
return file.CreateReadStream();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,8 @@ public async Task UseAutoServerClose_ClosingHandler_ShouldReturnFalse() {

// Act
app.UseAutoServerClose();
NetClosingDelegate? capturedHandler = mockEvents.WindowClosing.Snapshot.LastOrDefault();
bool? result = capturedHandler?.Invoke(new object(), EventArgs.Empty);
Func<IInfiniFrameWindow, EventArgs?, bool>? capturedHandler = mockEvents.WindowClosing.Snapshot.LastOrDefault();
bool? result = capturedHandler?.Invoke(mockWindow, EventArgs.Empty);

// Assert
await Assert.That(capturedHandler).IsNotNull();
Expand All @@ -152,8 +152,8 @@ public async Task UseAutoServerClose_ClosingHandler_ShouldInitiateStopAsync() {
app.UseAutoServerClose();

// Act
NetClosingDelegate? capturedHandler = mockEvents.WindowClosing.Snapshot.LastOrDefault();
capturedHandler?.Invoke(new object(), EventArgs.Empty);
Func<IInfiniFrameWindow, EventArgs?, bool>? capturedHandler = mockEvents.WindowClosing.Snapshot.LastOrDefault();
capturedHandler?.Invoke(mockWindow, EventArgs.Empty);

var appLifetime = webApp.Services.GetRequiredService<IHostApplicationLifetime>();
DateTime deadline = DateTime.UtcNow.AddSeconds(2);
Expand Down
11 changes: 6 additions & 5 deletions tests/InfiniFrameTests/InfiniFrameWindowBuilderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using NSubstitute;

namespace InfiniFrameTests;
// ---------------------------------------------------------------------------------------------------------------------
// Code
// ---------------------------------------------------------------------------------------------------------------------
public class InfiniFrameWindowBuilderTests {
private static Stream? EmptyHandler(object sender, string scheme, string url, out string? contentType) {
private static Stream? EmptyHandler(IInfiniFrameWindow sender, string scheme, string url, out string? contentType) {
_ = sender;
_ = scheme;
_ = url;
Expand Down Expand Up @@ -148,15 +149,15 @@ public async Task CreateSnapshot_ReRegisteringSameScheme_DoesNotMultiplyDelegate
.Where(static item => item.Key == "app")
.Select(static item => item.Value)
.FirstOrDefault();
copiedHandler?.Invoke(this, "app", "app://resource", out string? _);
copiedHandler?.Invoke(Substitute.For<IInfiniFrameWindow>(), "app", "app://resource", out string? _);

// Assert
await Assert.That(found).IsTrue();
await Assert.That(copiedHandler).IsNotNull();
await Assert.That(callCount).IsEqualTo(2);
return;

Stream? CountingHandler(object sender, string scheme, string url, out string? contentType) {
Stream? CountingHandler(IInfiniFrameWindow sender, string scheme, string url, out string? contentType) {
_ = sender;
_ = scheme;
_ = url;
Expand Down Expand Up @@ -186,8 +187,8 @@ public async Task CreateSnapshot_ReRegisteringSameScheme_RemainsStableAcrossRepe
int firstRegisteredCount = first.CustomSchemes.OrderedSchemeNames.Distinct(StringComparer.Ordinal).Count();
int secondRegisteredCount = second.CustomSchemes.OrderedSchemeNames.Distinct(StringComparer.Ordinal).Count();

firstHandler?.Invoke(this, "app", "app://resource1", out string? _);
secondHandler?.Invoke(this, "app", "app://resource2", out string? _);
firstHandler?.Invoke(Substitute.For<IInfiniFrameWindow>(), "app", "app://resource1", out string? _);
secondHandler?.Invoke(Substitute.For<IInfiniFrameWindow>(), "app", "app://resource2", out string? _);

// Assert
await Assert.That(foundFirst).IsTrue();
Expand Down
Loading
Loading